at main 3.4 kB view raw
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}