@@ -91,15 +91,19 @@ class MatchController extends Notifier<MatchState> {
9191 return state;
9292 }
9393
94- Future <void > _load (String myPetId) async {
94+ // When [silent] is true the loading flag is NOT set, so the UI avoids a
95+ // full-screen spinner. Use this for background refreshes (e.g. after a like).
96+ Future <void > _load (String myPetId, {bool silent = false }) async {
9597 final gen = ++ _loadGeneration;
9698 final userId = ref.read (authProvider).user? .id;
9799 if (userId == null ) {
98- state = state.copyWith (isLoading: false );
100+ if ( ! silent) state = state.copyWith (isLoading: false );
99101 return ;
100102 }
101103
102- state = state.copyWith (isLoading: true , clearError: true );
104+ if (! silent) state = state.copyWith (isLoading: true , clearError: true );
105+
106+ _currentDiscoveryPetId = myPetId;
103107
104108 try {
105109 final futures = await Future .wait ([
@@ -143,6 +147,12 @@ class MatchController extends Notifier<MatchState> {
143147 /// screen so the global active pet remains unchanged.
144148 Future <void > load (String petId) async => _load (petId);
145149
150+ /// The pet ID that was most recently loaded into this controller.
151+ /// Tracks which pet the discovery screen is currently browsing for,
152+ /// even when it differs from the global [activePetProvider] .
153+ String ? get currentDiscoveryPetId => _currentDiscoveryPetId;
154+ String ? _currentDiscoveryPetId;
155+
146156 void setFilterBreed (String ? breed) {
147157 final activePet = ref.read (activePetProvider);
148158 debugPrint (
@@ -199,12 +209,32 @@ class MatchController extends Notifier<MatchState> {
199209 }).toList ();
200210 }
201211
202- Future <bool > sendLikeRequest (String receiverPetId) async {
203- final activePet = ref.read (activePetProvider);
204- if (activePet == null ) return false ;
212+ /// Send a like/match request from the currently-browsing pet to [receiverPetId] .
213+ ///
214+ /// [fromPetId] should be the pet selected in the Discovery tab
215+ /// (from [discoveryActivePetIdProvider] ). It defaults to the global
216+ /// [activePetProvider] only as a fallback.
217+ Future <bool > sendLikeRequest (
218+ String receiverPetId, {
219+ String ? fromPetId,
220+ }) async {
221+ // Resolve the sender: prefer the explicitly passed discovery pet,
222+ // fall back to _currentDiscoveryPetId, then the global active pet.
223+ final myPets = ref.read (petProvider).myPets;
224+ final targetId = fromPetId ?? _currentDiscoveryPetId;
225+ PetModel ? senderPet;
226+ if (targetId != null ) {
227+ try {
228+ senderPet = myPets.firstWhere ((p) => p.id == targetId);
229+ } catch (_) {
230+ senderPet = null ;
231+ }
232+ }
233+ senderPet ?? = ref.read (activePetProvider);
234+ if (senderPet == null ) return false ;
205235
206236 // Prevent liking own pets
207- final myPetIds = ref. read (petProvider). myPets.map ((p) => p.id).toSet ();
237+ final myPetIds = myPets.map ((p) => p.id).toSet ();
208238 if (myPetIds.contains (receiverPetId)) {
209239 state = state.copyWith (error: 'You cannot like your own pet.' );
210240 return false ;
@@ -221,9 +251,11 @@ class MatchController extends Notifier<MatchState> {
221251
222252 try {
223253 await matchRepository.sendLikeRequest (
224- senderPetId: activePet .id,
254+ senderPetId: senderPet .id,
225255 receiverPetId: receiverPetId,
226256 );
257+
258+ // Optimistically remove the liked pet from the in-memory list.
227259 final discoveryPets =
228260 state.discoveryPets.where ((p) => p.id != receiverPetId).toList ();
229261 final allDiscoveryPets =
@@ -239,16 +271,17 @@ class MatchController extends Notifier<MatchState> {
239271 targetUserId: receiverPet.userId,
240272 title: 'New breeding interest' ,
241273 body:
242- '${activePet .name } is interested in breeding with ${receiverPet .name }.' ,
274+ '${senderPet .name } is interested in breeding with ${receiverPet .name }.' ,
243275 type: 'match_request' ,
244276 entityType: 'match_request' ,
245- entityId: activePet .id,
246- actorPetId: activePet .id,
277+ entityId: senderPet .id,
278+ actorPetId: senderPet .id,
247279 );
248280 }
249281
250- // Refresh sent requests
251- _load (activePet.id);
282+ // Silent background refresh for the correct (discovery-selected) pet —
283+ // does NOT show a loading spinner, so the UI transition is seamless.
284+ _load (senderPet.id, silent: true );
252285 return true ;
253286 } catch (e) {
254287 state = state.copyWith (error: 'Could not send request: $e ' );
@@ -296,3 +329,14 @@ class MatchController extends Notifier<MatchState> {
296329final matchProvider = NotifierProvider <MatchController , MatchState >(() {
297330 return MatchController ();
298331});
332+
333+ /// Aggregated incoming match requests for ALL of the current user's pets.
334+ /// Used by the Notifications screen so the Requests tab always shows the
335+ /// full picture regardless of which pet is selected in the Discovery tab.
336+ final allMatchRequestsProvider =
337+ FutureProvider <List <MatchRequestModel >>((ref) async {
338+ final myPets = ref.watch (petProvider).myPets;
339+ if (myPets.isEmpty) return [];
340+ final petIds = myPets.map ((p) => p.id).toList ();
341+ return matchRepository.fetchAllMyRequests (petIds);
342+ });
0 commit comments