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}