Main coves client
1// Comment data models for Coves
2//
3// These models match the backend response structure from:
4// /xrpc/social.coves.community.comment.getComments
5
6import 'post.dart';
7
8class CommentsResponse {
9 CommentsResponse({required this.post, this.cursor, required this.comments});
10
11 factory CommentsResponse.fromJson(Map<String, dynamic> json) {
12 // Handle null comments array from backend
13 final commentsData = json['comments'];
14 final List<ThreadViewComment> commentsList;
15
16 if (commentsData == null) {
17 // Backend returned null, use empty list
18 commentsList = [];
19 } else {
20 // Parse comment items
21 commentsList =
22 (commentsData as List<dynamic>)
23 .map(
24 (item) =>
25 ThreadViewComment.fromJson(item as Map<String, dynamic>),
26 )
27 .toList();
28 }
29
30 return CommentsResponse(
31 post: json['post'],
32 cursor: json['cursor'] as String?,
33 comments: commentsList,
34 );
35 }
36
37 final dynamic post;
38 final String? cursor;
39 final List<ThreadViewComment> comments;
40}
41
42class ThreadViewComment {
43 ThreadViewComment({
44 required this.comment,
45 this.replies,
46 this.hasMore = false,
47 });
48
49 factory ThreadViewComment.fromJson(Map<String, dynamic> json) {
50 return ThreadViewComment(
51 comment: CommentView.fromJson(json['comment'] as Map<String, dynamic>),
52 replies:
53 json['replies'] != null
54 ? (json['replies'] as List<dynamic>)
55 .map(
56 (item) => ThreadViewComment.fromJson(
57 item as Map<String, dynamic>,
58 ),
59 )
60 .toList()
61 : null,
62 hasMore: json['hasMore'] as bool? ?? false,
63 );
64 }
65
66 final CommentView comment;
67 final List<ThreadViewComment>? replies;
68 final bool hasMore;
69}
70
71class CommentView {
72 CommentView({
73 required this.uri,
74 required this.cid,
75 required this.content,
76 this.contentFacets,
77 required this.createdAt,
78 required this.indexedAt,
79 required this.author,
80 required this.post,
81 this.parent,
82 required this.stats,
83 this.viewer,
84 this.embed,
85 });
86
87 factory CommentView.fromJson(Map<String, dynamic> json) {
88 return CommentView(
89 uri: json['uri'] as String,
90 cid: json['cid'] as String,
91 content: json['content'] as String,
92 contentFacets:
93 json['contentFacets'] != null
94 ? (json['contentFacets'] as List<dynamic>)
95 .map((f) => PostFacet.fromJson(f as Map<String, dynamic>))
96 .toList()
97 : null,
98 createdAt: DateTime.parse(json['createdAt'] as String),
99 indexedAt: DateTime.parse(json['indexedAt'] as String),
100 author: AuthorView.fromJson(json['author'] as Map<String, dynamic>),
101 post: CommentRef.fromJson(json['post'] as Map<String, dynamic>),
102 parent:
103 json['parent'] != null
104 ? CommentRef.fromJson(json['parent'] as Map<String, dynamic>)
105 : null,
106 stats: CommentStats.fromJson(json['stats'] as Map<String, dynamic>),
107 viewer:
108 json['viewer'] != null
109 ? CommentViewerState.fromJson(
110 json['viewer'] as Map<String, dynamic>,
111 )
112 : null,
113 embed: json['embed'],
114 );
115 }
116
117 final String uri;
118 final String cid;
119 final String content;
120 final List<PostFacet>? contentFacets;
121 final DateTime createdAt;
122 final DateTime indexedAt;
123 final AuthorView author;
124 final CommentRef post;
125 final CommentRef? parent;
126 final CommentStats stats;
127 final CommentViewerState? viewer;
128 final dynamic embed;
129}
130
131class CommentRef {
132 CommentRef({required this.uri, required this.cid});
133
134 factory CommentRef.fromJson(Map<String, dynamic> json) {
135 return CommentRef(uri: json['uri'] as String, cid: json['cid'] as String);
136 }
137
138 final String uri;
139 final String cid;
140}
141
142class CommentStats {
143 CommentStats({this.upvotes = 0, this.downvotes = 0, this.score = 0});
144
145 factory CommentStats.fromJson(Map<String, dynamic> json) {
146 return CommentStats(
147 upvotes: json['upvotes'] as int? ?? 0,
148 downvotes: json['downvotes'] as int? ?? 0,
149 score: json['score'] as int? ?? 0,
150 );
151 }
152
153 final int upvotes;
154 final int downvotes;
155 final int score;
156}
157
158class CommentViewerState {
159 CommentViewerState({this.vote});
160
161 factory CommentViewerState.fromJson(Map<String, dynamic> json) {
162 return CommentViewerState(vote: json['vote'] as String?);
163 }
164
165 final String? vote;
166}