Main coves client
1import 'package:coves_flutter/models/coves_session.dart';
2import 'package:coves_flutter/providers/vote_provider.dart';
3import 'package:flutter/foundation.dart';
4
5/// Mock CommentsProvider for testing
6class MockCommentsProvider extends ChangeNotifier {
7 final String postUri;
8 final String postCid;
9
10 MockCommentsProvider({
11 required this.postUri,
12 required this.postCid,
13 });
14
15 final ValueNotifier<DateTime?> currentTimeNotifier = ValueNotifier(null);
16
17 @override
18 void dispose() {
19 currentTimeNotifier.dispose();
20 super.dispose();
21 }
22}
23
24/// Mock AuthProvider for testing
25class MockAuthProvider extends ChangeNotifier {
26 bool _isAuthenticated = false;
27 bool _isLoading = false;
28 String? _error;
29 String? _did;
30 String? _handle;
31 CovesSession? _session;
32
33 bool get isAuthenticated => _isAuthenticated;
34 bool get isLoading => _isLoading;
35 String? get error => _error;
36 String? get did => _did;
37 String? get handle => _handle;
38 CovesSession? get session => _session;
39
40 void setAuthenticated({required bool value, String? did}) {
41 _isAuthenticated = value;
42 _did = did ?? 'did:plc:testuser';
43 notifyListeners();
44 }
45
46 Future<void> signIn(String handle) async {
47 _isAuthenticated = true;
48 _handle = handle;
49 _did = 'did:plc:testuser';
50 notifyListeners();
51 }
52
53 Future<void> signOut() async {
54 _isAuthenticated = false;
55 _did = null;
56 _handle = null;
57 _session = null;
58 notifyListeners();
59 }
60
61 Future<void> initialize() async {
62 _isLoading = false;
63 }
64
65 Future<String?> getAccessToken() async {
66 return _isAuthenticated ? 'mock_access_token' : null;
67 }
68
69 void clearError() {
70 _error = null;
71 notifyListeners();
72 }
73}
74
75/// Mock VoteProvider for testing
76class MockVoteProvider extends ChangeNotifier {
77 final Map<String, VoteState> _votes = {};
78 final Map<String, int> _scoreAdjustments = {};
79 final Map<String, bool> _pendingRequests = {};
80
81 bool isLiked(String postUri) {
82 return _votes[postUri]?.direction == 'up' &&
83 !(_votes[postUri]?.deleted ?? false);
84 }
85
86 int getAdjustedScore(String postUri, int originalScore) {
87 final adjustment = _scoreAdjustments[postUri] ?? 0;
88 return originalScore + adjustment;
89 }
90
91 VoteState? getVoteState(String postUri) => _votes[postUri];
92
93 bool isPending(String postUri) => _pendingRequests[postUri] ?? false;
94
95 Future<bool> toggleVote({
96 required String postUri,
97 required String postCid,
98 String direction = 'up',
99 }) async {
100 final currentlyLiked = isLiked(postUri);
101
102 if (currentlyLiked) {
103 // Removing vote
104 _votes[postUri] = VoteState(direction: direction, deleted: true);
105 _scoreAdjustments[postUri] = (_scoreAdjustments[postUri] ?? 0) - 1;
106 } else {
107 // Adding vote
108 _votes[postUri] = VoteState(direction: direction, deleted: false);
109 _scoreAdjustments[postUri] = (_scoreAdjustments[postUri] ?? 0) + 1;
110 }
111
112 notifyListeners();
113 return !currentlyLiked;
114 }
115
116 void setVoteState({required String postUri, required bool liked}) {
117 if (liked) {
118 _votes[postUri] = const VoteState(direction: 'up', deleted: false);
119 } else {
120 _votes.remove(postUri);
121 }
122 notifyListeners();
123 }
124
125 void setInitialVoteState({
126 required String postUri,
127 String? voteDirection,
128 String? voteUri,
129 }) {
130 if (voteDirection != null) {
131 String? rkey;
132 if (voteUri != null) {
133 final parts = voteUri.split('/');
134 if (parts.isNotEmpty) {
135 rkey = parts.last;
136 }
137 }
138
139 _votes[postUri] = VoteState(
140 direction: voteDirection,
141 uri: voteUri,
142 rkey: rkey,
143 deleted: false,
144 );
145
146 _scoreAdjustments.remove(postUri);
147 } else {
148 _votes.remove(postUri);
149 }
150 }
151
152 void clear() {
153 _votes.clear();
154 _pendingRequests.clear();
155 _scoreAdjustments.clear();
156 notifyListeners();
157 }
158}