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({required 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(direction: direction, deleted: true);
91 _scoreAdjustments[postUri] = (_scoreAdjustments[postUri] ?? 0) - 1;
92 } else {
93 // Adding vote
94 _votes[postUri] = VoteState(direction: direction, deleted: false);
95 _scoreAdjustments[postUri] = (_scoreAdjustments[postUri] ?? 0) + 1;
96 }
97
98 notifyListeners();
99 return !currentlyLiked;
100 }
101
102 void setVoteState({required String postUri, required bool liked}) {
103 if (liked) {
104 _votes[postUri] = const VoteState(direction: 'up', deleted: false);
105 } else {
106 _votes.remove(postUri);
107 }
108 notifyListeners();
109 }
110
111 void loadInitialVotes(Map<String, VoteInfo> votes) {
112 for (final entry in votes.entries) {
113 final postUri = entry.key;
114 final voteInfo = entry.value;
115
116 _votes[postUri] = VoteState(
117 direction: voteInfo.direction,
118 uri: voteInfo.voteUri,
119 rkey: voteInfo.rkey,
120 deleted: false,
121 );
122
123 _scoreAdjustments.remove(postUri);
124 }
125 notifyListeners();
126 }
127
128 void clear() {
129 _votes.clear();
130 _pendingRequests.clear();
131 _scoreAdjustments.clear();
132 notifyListeners();
133 }
134}