feat(models): add ViewerState to PostView for vote tracking

Add ViewerState class to represent the viewer's relationship with posts:
- vote: direction ("up", "down", or null)
- voteUri: AT-URI of the vote record
- saved: bookmark status
- tags: user-applied tags

This enables the feed to include viewer-specific state from the backend,
allowing proper initialization of vote UI state on feed refresh.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Changed files
+50 -2
lib
+9 -2
lib/models/comment.dart
···
}
class CommentViewerState {
-
CommentViewerState({this.vote});
+
CommentViewerState({this.vote, this.voteUri});
factory CommentViewerState.fromJson(Map<String, dynamic> json) {
-
return CommentViewerState(vote: json['vote'] as String?);
+
return CommentViewerState(
+
vote: json['vote'] as String?,
+
voteUri: json['voteUri'] as String?,
+
);
}
+
/// Vote direction: "up", "down", or null if not voted
final String? vote;
+
+
/// AT-URI of the vote record (if backend provides it)
+
final String? voteUri;
}
+41
lib/models/post.dart
···
final FeedReason? reason;
}
+
class ViewerState {
+
ViewerState({
+
this.vote,
+
this.voteUri,
+
this.saved = false,
+
this.savedUri,
+
this.tags,
+
});
+
+
factory ViewerState.fromJson(Map<String, dynamic> json) {
+
return ViewerState(
+
vote: json['vote'] as String?,
+
voteUri: json['voteUri'] as String?,
+
saved: json['saved'] as bool? ?? false,
+
savedUri: json['savedUri'] as String?,
+
tags: (json['tags'] as List<dynamic>?)?.cast<String>(),
+
);
+
}
+
+
/// Vote direction: "up", "down", or null if not voted
+
final String? vote;
+
+
/// AT-URI of the vote record
+
final String? voteUri;
+
+
/// Whether the post is saved/bookmarked
+
final bool saved;
+
+
/// AT-URI of the saved record
+
final String? savedUri;
+
+
/// User-applied tags
+
final List<String>? tags;
+
}
+
class PostView {
PostView({
required this.uri,
···
required this.stats,
this.embed,
this.facets,
+
this.viewer,
});
factory PostView.fromJson(Map<String, dynamic> json) {
···
.map((f) => PostFacet.fromJson(f as Map<String, dynamic>))
.toList()
: null,
+
viewer:
+
json['viewer'] != null
+
? ViewerState.fromJson(json['viewer'] as Map<String, dynamic>)
+
: null,
);
}
final String uri;
···
final PostStats stats;
final PostEmbed? embed;
final List<PostFacet>? facets;
+
final ViewerState? viewer;
}
class AuthorView {