Skip to content

Commit 80482e0

Browse files
committed
merge
1 parent 79a8ec1 commit 80482e0

1 file changed

Lines changed: 66 additions & 75 deletions

File tree

lam7a/lib/features/tweet/services/tweet_api_service_impl.dart

Lines changed: 66 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -164,98 +164,61 @@ class TweetsApiServiceImpl implements TweetsApiService {
164164

165165
for (final raw in postsJson) {
166166
if (raw is! Map) continue;
167-
final json = raw as Map;
167+
final json = raw as Map<String, dynamic>;
168+
169+
// Prefer the new transformed post shape from backend (with
170+
// originalPostData for replies / reposts / quotes). This ensures
171+
// replies and quotes carry their parent tweet tree via
172+
// TweetModel.originalTweet.
173+
try {
174+
if (json.containsKey('postId') && json.containsKey('date')) {
175+
final tweet = TweetModel.fromJsonPosts(json);
176+
177+
final tweetId = tweet.id;
178+
final isLikedByMe = json['isLikedByMe'] ?? false;
179+
final isRepostedByMe = json['isRepostedByMe'] ?? false;
180+
final isRepost = json['isRepost'] ?? false;
181+
final isQuote = json['isQuote'] ?? false;
182+
183+
final existingFlags = _interactionFlags[tweetId] ?? <String, bool>{};
184+
_interactionFlags[tweetId] = {
185+
...existingFlags,
186+
'isLikedByMe': isLikedByMe,
187+
'isRepostedByMe': isRepostedByMe,
188+
'isRepost': isRepost,
189+
'isQuote': isQuote,
190+
};
191+
192+
tweets.add(tweet);
193+
continue;
194+
}
195+
} catch (e) {
196+
print('⚠️ Failed to parse transformed feed post via fromJsonPosts, falling back: $e');
197+
}
168198

199+
// Fallback: legacy mapping for older backend shapes.
169200
final tweetId =
170201
(json['postId'] ??
171202
json['id'] ??
172203
DateTime.now().millisecondsSinceEpoch)
173204
.toString();
174205

175-
// Basic user info
176206
final username = json['username']?.toString();
177207
final authorName = json['name']?.toString();
178208
final authorProfileImage = json['avatar']?.toString();
179209

180210
int parseInt(dynamic v) =>
181211
v == null ? 0 : (v is int ? v : int.tryParse(v.toString()) ?? 0);
182212

183-
// Counts from feed
184213
final likes = parseInt(json['likesCount']);
185214
final reposts = parseInt(json['retweetsCount']);
186215
final comments = parseInt(json['commentsCount']);
187216

188-
// Interaction and repost metadata flags
189217
final isLikedByMe = json['isLikedByMe'] ?? false;
190218
final isRepostedByMe = json['isRepostedByMe'] ?? false;
191219
final isRepost = json['isRepost'] ?? false;
192220
final isQuote = json['isQuote'] ?? false;
193221

194-
// Original post data for reposts/quotes (to show nested parent tweet)
195-
Map<String, dynamic>? originalTweetJson;
196-
final original = json['originalPostData'];
197-
if (original is Map) {
198-
final o = original;
199-
200-
final originalId =
201-
(o['postId'] ?? o['id'] ?? DateTime.now().millisecondsSinceEpoch)
202-
.toString();
203-
204-
final originalUserId = (o['userId'] ?? o['user_id'] ?? '0')
205-
.toString();
206-
207-
final rawDate = o['date'] ?? o['createdAt'] ?? o['created_at'];
208-
String originalDateString;
209-
if (rawDate is String) {
210-
originalDateString = rawDate;
211-
} else if (rawDate is DateTime) {
212-
originalDateString = rawDate.toIso8601String();
213-
} else {
214-
originalDateString = DateTime.now().toIso8601String();
215-
}
216-
217-
final originalLikes = parseInt(o['likesCount']);
218-
final originalReposts = parseInt(o['retweetsCount']);
219-
final originalComments = parseInt(o['commentsCount']);
220-
221-
final originalImageUrls = <String>[];
222-
final originalVideoUrls = <String>[];
223-
if (o['media'] is List) {
224-
for (final m in (o['media'] as List)) {
225-
if (m is! Map) continue;
226-
final url = m['url']?.toString();
227-
final type = m['type']?.toString();
228-
if (url == null || url.isEmpty) continue;
229-
if (type == 'VIDEO') {
230-
originalVideoUrls.add(url);
231-
} else {
232-
originalImageUrls.add(url);
233-
}
234-
}
235-
}
236-
237-
originalTweetJson = <String, dynamic>{
238-
'id': originalId,
239-
'userId': originalUserId,
240-
'body': (o['text'] ?? o['content'] ?? '').toString(),
241-
'date': originalDateString,
242-
'username': o['username']?.toString(),
243-
'authorName': o['name']?.toString(),
244-
'authorProfileImage': o['avatar']?.toString(),
245-
'likes': originalLikes,
246-
'repost': originalReposts,
247-
'comments': originalComments,
248-
'views': 0,
249-
'qoutes': 0,
250-
'bookmarks': 0,
251-
'mediaImages': originalImageUrls,
252-
'mediaVideos': originalVideoUrls,
253-
'isRepost': false,
254-
'isQuote': false,
255-
};
256-
}
257-
258-
// Media
259222
final imageUrls = <String>[];
260223
final videoUrls = <String>[];
261224
if (json['media'] is List) {
@@ -296,13 +259,8 @@ class TweetsApiServiceImpl implements TweetsApiService {
296259
'isQuote': isQuote,
297260
};
298261

299-
if (originalTweetJson != null) {
300-
mappedJson['originalTweet'] = originalTweetJson;
301-
}
302-
303262
final tweet = TweetModel.fromJson(mappedJson);
304263

305-
// Store interaction flags and repost metadata for this tweet
306264
final existingFlags = _interactionFlags[tweetId] ?? <String, bool>{};
307265
_interactionFlags[tweetId] = {
308266
...existingFlags,
@@ -406,7 +364,40 @@ class TweetsApiServiceImpl implements TweetsApiService {
406364
final dynamic json = (data is List && data.isNotEmpty)
407365
? data.first
408366
: data;
409-
// Map backend fields to frontend model (supports both transformed and legacy shapes)
367+
// If backend returns the new transformed post shape (with top-level
368+
// postId/date/username/name/avatar and optional originalPostData), use
369+
// the dedicated mapper so quotes and replies include their parent tree.
370+
if (json is Map<String, dynamic> &&
371+
json.containsKey('postId') &&
372+
json.containsKey('date') &&
373+
(json.containsKey('username') ||
374+
json.containsKey('name') ||
375+
json.containsKey('avatar'))) {
376+
try {
377+
final tweet = TweetModel.fromJsonPosts(json);
378+
final tweetId = tweet.id;
379+
380+
final isLikedByMe = json['isLikedByMe'] ?? false;
381+
final isRepostedByMe = json['isRepostedByMe'] ?? false;
382+
final isRepost = json['isRepost'] ?? false;
383+
final isQuote = json['isQuote'] ?? false;
384+
385+
final existingFlags = _interactionFlags[tweetId] ?? <String, bool>{};
386+
_interactionFlags[tweetId] = {
387+
...existingFlags,
388+
'isLikedByMe': isLikedByMe,
389+
'isRepostedByMe': isRepostedByMe,
390+
'isRepost': isRepost,
391+
'isQuote': isQuote,
392+
};
393+
394+
return tweet;
395+
} catch (e) {
396+
print('⚠️ Failed to parse getTweetById via fromJsonPosts, falling back: $e');
397+
}
398+
}
399+
400+
// Map backend fields to frontend model (supports legacy and mixed shapes)
410401
final tweetId =
411402
(json['postId'] ??
412403
json['id'] ??

0 commit comments

Comments
 (0)