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