fix(flutter): 추억 보관함·순서 바꾸기도 서버 실패를 견디게

서버에 저장하면서 실패할 수 있게 된 남은 흐름을 정리했다.

- 보관하기·다시 불러오기는 성공했을 때만 화면을 옮기고 토스트를 띄운다
- 우리 아이 순서 바꾸기는 화면에 먼저 반영하고, 저장하지 못하면 원래 순서로 되돌린다

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 18:35:11 +09:00
parent 2c1d1cc97d
commit 9cb660a0ac
5 changed files with 25 additions and 13 deletions
@@ -37,7 +37,7 @@ class ArchivedPetPage extends ConsumerWidget {
final String petId;
Future<void> _restore(BuildContext context, WidgetRef ref) async {
await ref.read(archiveActionsProvider).restore(petId);
if (!await ref.read(archiveActionsProvider).restore(petId)) return;
if (context.mounted) context.go(AppRoutes.archive);
}
@@ -78,11 +78,11 @@ class _PetArchiveMovePageState extends ConsumerState<PetArchiveMovePage> {
Future<void> _submit(Pet pet, DateTime from) async {
final memo = _memo.text.trim();
await ref.read(archiveActionsProvider).archive(
final moved = await ref.read(archiveActionsProvider).archive(
pet.id,
PetArchive(from: from, to: _to, archivedAt: DateTime.now(), memo: memo.isEmpty ? null : memo),
);
if (mounted) context.go(AppRoutes.myPage);
if (moved && mounted) context.go(AppRoutes.myPage);
}
@override
@@ -1,4 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tma_app/core/api/api_guard.dart';
import 'package:tma_app/features/pet/domain/pet_archive.dart';
import 'package:tma_app/features/pet/presentation/providers/pet_providers.dart';
import 'package:tma_app/features/schedule/presentation/providers/schedule_providers.dart';
@@ -11,17 +12,20 @@ class ArchiveActions {
final Ref _ref;
/// 아이를 보관함으로 옮긴다. 일정은 지우고(여러 아이 일정이면 그 아이만 뗀다),
/// 다이어리·펫 명함·정보는 그대로 두어 보관함에서 다시 볼 수 있게 한다.
Future<void> archive(String petId, PetArchive archive) async {
await _ref.read(petListProvider.notifier).archivePet(petId, archive);
/// 다이어리·펫 명함·정보는 그대로 두어 보관함에서 다시 볼 수 있게 한다 (서버 모드는 일정 정리를 서버가 한다).
/// 옮기지 못하면 false — 실패 알림은 인터셉터가 띄웠다.
Future<bool> archive(String petId, PetArchive archive) async {
if (!await succeeded(_ref.read(petListProvider.notifier).archivePet(petId, archive))) return false;
await _ref.read(scheduleProvider.notifier).dropTarget(petId);
_ref.read(toastProvider.notifier).show('추억보관함에 보관했어요.', tone: ToastTone.memory);
return true;
}
/// 보관함에서 다시 불러온다 — 지운 일정은 돌아오지 않는다
Future<void> restore(String petId) async {
await _ref.read(petListProvider.notifier).restorePet(petId);
/// 보관함에서 다시 불러온다 — 지운 일정은 돌아오지 않는다. 불러오지 못하면 false
Future<bool> restore(String petId) async {
if (!await succeeded(_ref.read(petListProvider.notifier).restorePet(petId))) return false;
_ref.read(toastProvider.notifier).show('다시 불러왔어요');
return true;
}
}
@@ -3,6 +3,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:tma_app/core/api/api_guard.dart';
import 'package:tma_app/core/constants/app_colors.dart';
import 'package:tma_app/core/constants/app_sizes.dart';
import 'package:tma_app/core/router/app_routes.dart';
@@ -57,7 +58,7 @@ class _HomePetsSectionState extends ConsumerState<HomePetsSection> {
selectedId: selected?.id,
onSelect: (id) => ref.read(selectedPetIdProvider.notifier).select(id),
// 꾹 눌러 끌어서 우리 아이 순서를 바꾼다
onReorder: (ids) => unawaited(ref.read(petListProvider.notifier).reorder(ids)),
onReorder: (ids) => unawaited(succeeded(ref.read(petListProvider.notifier).reorder(ids))),
),
if (selected != null) ...[
const SizedBox(height: 20),
@@ -39,10 +39,17 @@ class PetListNotifier extends AsyncNotifier<List<Pet>> {
Future<void> archivePet(String id, PetArchive archive) async => _replace(await _repo.archive(id, archive));
/// 우리 아이 순서 바꾸기 — 화면에는 바로 반영하고 저장한다
/// 우리 아이 순서 바꾸기 — 화면에는 바로 반영하고 저장한다. 저장하지 못하면 원래 순서로 되돌린다
Future<void> reorder(List<String> ids) async {
state = AsyncData(reorderPets(state.value ?? const <Pet>[], ids));
await _repo.reorder(ids);
final before = state.value ?? const <Pet>[];
state = AsyncData(reorderPets(before, ids));
try {
final saved = await _repo.reorder(ids);
if (ref.mounted) state = AsyncData(saved);
} on Exception {
if (ref.mounted) state = AsyncData(before);
rethrow;
}
}
Future<void> restorePet(String id) async => _replace(await _repo.restore(id));