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}