Grain flutter app
1import 'package:grain/api.dart';
2import 'package:grain/models/comment.dart';
3import 'package:grain/models/gallery.dart';
4import 'package:grain/models/procedures/create_comment_request.dart';
5import 'package:grain/models/procedures/delete_comment_request.dart';
6import 'package:grain/providers/gallery_cache_provider.dart';
7import 'package:riverpod_annotation/riverpod_annotation.dart';
8
9part 'gallery_thread_cache_provider.g.dart';
10
11class GalleryThreadState {
12 final bool loading;
13 final bool error;
14 final Gallery? gallery;
15 final List<Comment> comments;
16 final String? errorMessage;
17 const GalleryThreadState({
18 this.loading = false,
19 this.error = false,
20 this.gallery,
21 this.comments = const [],
22 this.errorMessage,
23 });
24
25 GalleryThreadState copyWith({
26 bool? loading,
27 bool? error,
28 Gallery? gallery,
29 List<Comment>? comments,
30 String? errorMessage,
31 }) {
32 return GalleryThreadState(
33 loading: loading ?? this.loading,
34 error: error ?? this.error,
35 gallery: gallery ?? this.gallery,
36 comments: comments ?? this.comments,
37 errorMessage: errorMessage ?? this.errorMessage,
38 );
39 }
40}
41
42@Riverpod(keepAlive: false)
43class GalleryThread extends _$GalleryThread {
44 late String galleryUri;
45
46 @override
47 GalleryThreadState build(String galleryUriParam) {
48 galleryUri = galleryUriParam;
49 // Set initial state synchronously, schedule fetchThread async
50 Future.microtask(fetchThread);
51 return const GalleryThreadState(loading: true);
52 }
53
54 Future<void> fetchThread() async {
55 state = state.copyWith(loading: true, error: false);
56 try {
57 final thread = await apiService.getGalleryThread(uri: galleryUri);
58 state = state.copyWith(
59 gallery: thread?.gallery,
60 comments: thread?.comments ?? [],
61 loading: false,
62 error: false,
63 );
64 } catch (e) {
65 state = state.copyWith(loading: false, error: true, errorMessage: e.toString());
66 }
67 }
68
69 Future<bool> createComment({required String text, String? replyTo, String? focus}) async {
70 try {
71 final request = CreateCommentRequest(
72 text: text,
73 subject: galleryUri,
74 replyTo: replyTo,
75 focus: focus,
76 );
77 final res = await apiService.createComment(request: request);
78 if (res.commentUri.isNotEmpty) {
79 final thread = await apiService.getGalleryThread(uri: galleryUri);
80 if (thread != null) {
81 state = state.copyWith(gallery: thread.gallery, comments: thread.comments);
82 // Update the gallery cache with the latest gallery
83 ref.read(galleryCacheProvider.notifier).setGallery(thread.gallery);
84 } else {
85 await fetchThread();
86 }
87 return true;
88 }
89 } catch (_) {}
90 return false;
91 }
92
93 Future<bool> deleteComment(Comment comment) async {
94 final request = DeleteCommentRequest(uri: comment.uri);
95 final res = await apiService.deleteComment(request: request);
96 if (!res.success) return false;
97 final thread = await apiService.getGalleryThread(uri: galleryUri);
98 if (thread != null) {
99 state = state.copyWith(gallery: thread.gallery, comments: thread.comments);
100 // Update the gallery cache with the latest gallery
101 ref.read(galleryCacheProvider.notifier).setGallery(thread.gallery);
102 } else {
103 await fetchThread();
104 }
105 return true;
106 }
107}