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