I am creating a flutter app and this is the part of code where i am getting the error. I am using flutter_riverpod package as my provider
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:twitter_clone/common/common.dart';
import 'package:twitter_clone/features/tweet/controller/tweet_controller.dart';
class TweetList extends ConsumerWidget {
const TweetList({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return ref.watch(getTweetsProvider).when(
data: (tweets) {
return ListView.builder(
itemCount: tweets.length,
itemBuilder: (context, index) {
final tweet = tweets[index];
return Text(tweet.text);
},
);
},
error: (error, stackTrace) => ErrorText(
errorText: error.toString(),
),
loading: () => const Loader());
}
}
The ErrorText widget simply displays the error on screen
This is the controller class
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:twitter_clone/apis/storage_api.dart';
import 'package:twitter_clone/apis/tweet_api.dart';
import 'package:twitter_clone/core/core.dart';
import 'package:twitter_clone/features/auth/controller/auth_controller.dart';
import 'package:twitter_clone/models/tweet_model.dart';
final getTweetsProvider = FutureProvider((ref) {
final tweetController = ref.watch(tweetControllerProvider.notifier);
return tweetController.getTweets();
});
final tweetControllerProvider = StateNotifierProvider<TweetController, bool>(
(ref) {
return TweetController(
ref: ref,
tweetAPI: ref.watch(tweetAPIProvider),
storageAPI: ref.watch(storageAPIProvider),
);
},
);
class TweetController extends StateNotifier<bool> {
final TweetAPI _tweetAPI;
final StorageAPI _storageAPI;
final Ref _ref;
TweetController({
required Ref ref,
required TweetAPI tweetAPI,
required StorageAPI storageAPI,
}) : _ref = ref,
_tweetAPI = tweetAPI,
_storageAPI = storageAPI,
super(false);
Future<List<TweetModel>> getTweets() async {
final tweetList = await _tweetAPI.getTweets();
return tweetList
.map<TweetModel>((tweet) => TweetModel.fromMap(tweet.data))
.toList();
}
void shareTweet({
required List<File> images,
required String text,
required BuildContext context,
}) {
if (text.isEmpty) {
showSnackBar(context, 'Please enter text');
}
if (images.isNotEmpty) {
_shareImageTweet(
images: images,
text: text,
context: context,
);
} else {
_shareTextTweet(
text: text,
context: context,
);
}
}
void _shareImageTweet({
required List<File> images,
required String text,
required BuildContext context,
}) async {
state = true;
final hashTags = _getHashTagsFromText(text);
String link = _getLinkFromText(text);
final user = _ref.read(currentUserDetailsProvider).value!;
final imageLinks = await _storageAPI.uploadImages(images);
TweetModel tweetModel = TweetModel(
text: text,
hashTags: hashTags,
link: link,
imageLinks: imageLinks,
userId: user.uid,
tweetType: TweetType.image,
tweetedAt: DateTime.now(),
likes: const [],
commentIds: const [],
id: '',
reSharedCount: 0,
);
final res = await _tweetAPI.shareTweet(tweetModel);
state = false;
res.fold((l) => showSnackBar(context, l.message), (r) => null);
}
void _shareTextTweet({
required String text,
required BuildContext context,
}) async {
state = true;
final hashTags = _getHashTagsFromText(text);
String link = _getLinkFromText(text);
final user = _ref.read(currentUserDetailsProvider).value!;
TweetModel tweetModel = TweetModel(
text: text,
hashTags: hashTags,
link: link,
imageLinks: const [],
userId: user.uid,
tweetType: TweetType.text,
tweetedAt: DateTime.now(),
likes: const [],
commentIds: const [],
id: '',
reSharedCount: 0,
);
final res = await _tweetAPI.shareTweet(tweetModel);
state = false;
res.fold((l) => showSnackBar(context, l.message), (r) => null);
}
String _getLinkFromText(String text) {
String link = '';
List<String> wordsInSentence = text.split(' ');
for (String word in wordsInSentence) {
if (word.startsWith('https://') ||
word.startsWith('http://') ||
word.startsWith('www.')) {
link = word;
}
}
return link;
}
List<String> _getHashTagsFromText(String text) {
List<String> hashTags = [];
List<String> wordsInSentence = text.split(' ');
for (String word in wordsInSentence) {
if (word.startsWith('#')) {
hashTags.add(word);
}
}
return hashTags;
}
}
This is the api class
import 'package:appwrite/appwrite.dart';
import 'package:appwrite/models.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fpdart/fpdart.dart';
import 'package:twitter_clone/constants/appwrite_constants.dart';
import 'package:twitter_clone/core/core.dart';
import 'package:twitter_clone/models/tweet_model.dart';
final tweetAPIProvider = Provider((ref) {
return TweetAPI(db: ref.watch(appwriteDataBaseProvider));
});
abstract class ITweetAPI {
FutureEither<Document> shareTweet(TweetModel tweetModel);
Future<List<Document>> getTweets();
}
class TweetAPI implements ITweetAPI {
final Databases _db;
TweetAPI({required Databases db}) : _db = db;
@override
FutureEither<Document> shareTweet(TweetModel tweetModel) async {
try {
final document = await _db.createDocument(
databaseId: AppwriteConstants.databaseId,
collectionId: AppwriteConstants.tweetsCollectionId,
documentId: ID.unique(),
data: tweetModel.toMap(),
);
return right(document);
} on AppwriteException catch (e, st) {
return left(
Failure(e.message ?? "Some unexpected error occurred", st),
);
} catch (e, st) {
return left(
Failure(e.toString(), st),
);
}
}
@override
Future<List<Document>> getTweets() async {
final documents = await _db.listDocuments(
databaseId: AppwriteConstants.databaseId,
collectionId: AppwriteConstants.tweetsCollectionId,
);
return documents.documents;
}
}
and this is the model class
import 'package:flutter/foundation.dart';
import 'package:twitter_clone/core/core.dart';
@immutable
class TweetModel {
final String text;
final List<String> hashTags;
final String link;
final List<String> imageLinks;
final String userId;
final TweetType tweetType;
final DateTime tweetedAt;
final List<String> likes;
final List<String> commentIds;
final String id;
final int reSharedCount;
const TweetModel({
required this.text,
required this.hashTags,
required this.link,
required this.imageLinks,
required this.userId,
required this.tweetType,
required this.tweetedAt,
required this.likes,
required this.commentIds,
required this.id,
required this.reSharedCount,
});
Map<String, dynamic> toMap() {
return {
'text': text,
'hashTags': hashTags,
'link': link,
'imageLinks': imageLinks,
'userId': userId,
'tweetType': tweetType.type,
'tweetedAt': tweetedAt.millisecondsSinceEpoch,
'likes': likes,
'commentIds': commentIds,
'reSharedCount': reSharedCount,
};
}
factory TweetModel.fromMap(Map<String, dynamic> map) {
return TweetModel(
text: map['text'] as String,
hashTags: map['hashTags'] as List<String>,
link: map['link'] as String,
imageLinks: map['imageLinks'] as List<String>,
userId: map['userId'] as String,
tweetType: (map['tweetType'] as String).toTweetTypeEnum(),
tweetedAt: DateTime.fromMillisecondsSinceEpoch(map['tweetedAt']),
likes: map['likes'] as List<String>,
commentIds: map['commentIds'] as List<String>,
id: map['\$id'] as String,
reSharedCount: map['reSharedCount'] as int,
);
}
TweetModel copyWith({
String? text,
List<String>? hashTags,
String? link,
List<String>? imageLinks,
String? userId,
TweetType? tweetType,
DateTime? tweetedAt,
List<String>? likes,
List<String>? commentIds,
String? id,
int? reSharedCount,
}) {
return TweetModel(
text: text ?? this.text,
hashTags: hashTags ?? this.hashTags,
link: link ?? this.link,
imageLinks: imageLinks ?? this.imageLinks,
userId: userId ?? this.userId,
tweetType: tweetType ?? this.tweetType,
tweetedAt: tweetedAt ?? this.tweetedAt,
likes: likes ?? this.likes,
commentIds: commentIds ?? this.commentIds,
id: id ?? this.id,
reSharedCount: reSharedCount ?? this.reSharedCount,
);
}
}
I have tried different sources to look for the solution. I searched this site to but did not find the solution.Please do help I am stuck here.
I just changed the models fromMap function from this
factory TweetModel.fromMap(Map<String, dynamic> map) {
return TweetModel(
text: map['text'] as String,
hashTags: map['hashTags'] as List<String>,
link: map['link'] as String,
imageLinks: map['imageLinks'] as List<String>,
userId: map['userId'] as String,
tweetType: (map['tweetType'] as String).toTweetTypeEnum(),
tweetedAt: DateTime.fromMillisecondsSinceEpoch(map['tweetedAt']),
likes: map['likes'] as List<String>,
commentIds: map['commentIds'] as List<String>,
id: map['\$id'] as String,
reSharedCount: map['reSharedCount'] as int,
);
}
to this
factory TweetModel.fromMap(Map<String, dynamic> map) {
return TweetModel(
text: map['text'] ?? '',
hashtags: List<String>.from(map['hashtags']),
link: map['link'] ?? '',
imageLinks: List<String>.from(map['imageLinks']),
uid: map['uid'] ?? '',
tweetType: (map['tweetType'] as String).toTweetTypeEnum(),
tweetedAt: DateTime.fromMillisecondsSinceEpoch(map['tweetedAt']),
likes: List<String>.from(map['likes']),
commentIds: List<String>.from(map['commentIds']),
id: map['\$id'] ?? '',
reshareCount: map['reshareCount']?.toInt() ?? 0,
retweetedBy: map['retweetedBy'] ?? '',
repliedTo: map['repliedTo'] ?? '',
);
} and it worked.