feat: Add refresh token mechanism and sync request handling in home screen

This commit is contained in:
2026-05-18 20:12:52 +02:00
parent 7da87843cd
commit 75513da17d
3 changed files with 75 additions and 35 deletions
+8
View File
@@ -70,6 +70,7 @@ class _NotesAppState extends State<NotesApp>
_AppSection _currentSection = _AppSection.home;
SyncStatus _syncStatus = SyncStatus.idle;
String? _syncErrorMessage;
int _homeRefreshToken = 0;
@override
void initState() {
@@ -613,6 +614,10 @@ class _NotesAppState extends State<NotesApp>
return;
}
if (_syncStatus == SyncStatus.syncing) {
return;
}
setState(() {
_syncStatus = SyncStatus.syncing;
_syncErrorMessage = null;
@@ -634,6 +639,7 @@ class _NotesAppState extends State<NotesApp>
setState(() {
_syncStatus = SyncStatus.synced;
_syncErrorMessage = null;
_homeRefreshToken += 1;
});
// Reset to idle after 3 seconds
@@ -704,9 +710,11 @@ class _NotesAppState extends State<NotesApp>
key: const ValueKey<String>('home-screen'),
repository: repository,
onOpenSettings: _openSettings,
onRequestSync: _performSync,
onVaultInvalid: _resetLocalVaultData,
syncStatus: _syncStatus,
syncErrorMessage: _syncErrorMessage,
refreshToken: _homeRefreshToken,
)
: SettingsScreen(
key: const ValueKey<String>('settings-screen'),
+20 -13
View File
@@ -17,16 +17,20 @@ class HomeScreen extends StatefulWidget {
super.key,
required this.repository,
required this.onOpenSettings,
required this.onRequestSync,
this.onVaultInvalid,
this.syncStatus = SyncStatus.idle,
this.syncErrorMessage,
this.refreshToken = 0,
});
final NoteRepository repository;
final VoidCallback onOpenSettings;
final Future<void> Function() onRequestSync;
final Future<void> Function()? onVaultInvalid;
final SyncStatus syncStatus;
final String? syncErrorMessage;
final int refreshToken;
@override
State<HomeScreen> createState() => _HomeScreenState();
@@ -52,6 +56,14 @@ class _HomeScreenState extends State<HomeScreen> {
_loadNotes();
}
@override
void didUpdateWidget(covariant HomeScreen oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.refreshToken != widget.refreshToken) {
_loadNotes();
}
}
Future<void> _loadNotes() async {
try {
final List<Note> storedNotes = await widget.repository.loadNotes();
@@ -92,10 +104,9 @@ class _HomeScreenState extends State<HomeScreen> {
_notes = updatedNotes;
});
// Trigger sync after creating a note and refresh local list
// Trigger sync after creating a note.
try {
await widget.repository.performSync();
await _loadNotes();
await widget.onRequestSync();
} catch (_) {}
}
}
@@ -115,10 +126,9 @@ class _HomeScreenState extends State<HomeScreen> {
_notes = updatedNotes;
});
// Trigger sync after deleting a note and refresh local list
// Trigger sync after deleting a note.
try {
await widget.repository.performSync();
await _loadNotes();
await widget.onRequestSync();
} catch (_) {}
}
@@ -171,10 +181,9 @@ class _HomeScreenState extends State<HomeScreen> {
setState(() {
_notes = _normalizeNotes(updatedNotes);
});
// Trigger sync after editing a note and refresh local list
// Trigger sync after editing a note.
try {
await widget.repository.performSync();
await _loadNotes();
await widget.onRequestSync();
} catch (_) {}
}
}
@@ -212,10 +221,7 @@ class _HomeScreenState extends State<HomeScreen> {
? const _EmptyState()
: RefreshIndicator(
onRefresh: () async {
try {
await widget.repository.performSync();
} catch (_) {}
await _loadNotes();
await widget.onRequestSync();
},
child: MouseRegion(
cursor: _isDragging
@@ -520,6 +526,7 @@ class _HomeScreenState extends State<HomeScreen> {
trailingWidget: SyncStatusIndicator(
status: widget.syncStatus,
errorMessage: widget.syncErrorMessage,
onTap: widget.onRequestSync,
),
onSearchChanged: (String query) {
setState(() {
+47 -22
View File
@@ -11,57 +11,82 @@ class SyncStatusIndicator extends StatelessWidget {
const SyncStatusIndicator({
required this.status,
this.errorMessage,
this.onTap,
super.key,
});
final SyncStatus status;
final String? errorMessage;
final VoidCallback? onTap;
Widget _buildIndicator(Widget child) {
if (onTap == null) {
return child;
}
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: child,
),
);
}
@override
Widget build(BuildContext context) {
switch (status) {
case SyncStatus.idle:
return const Tooltip(
return Tooltip(
message: 'Sincronización en espera',
child: Icon(
Icons.cloud_outlined,
size: 16,
color: Colors.white38,
child: _buildIndicator(
const Icon(
Icons.cloud_outlined,
size: 16,
color: Colors.white38,
),
),
);
case SyncStatus.syncing:
return const Tooltip(
return Tooltip(
message: 'Sincronizando...',
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Color.fromARGB(255, 150, 150, 150),
child: _buildIndicator(
const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Color.fromARGB(255, 150, 150, 150),
),
),
),
),
);
case SyncStatus.synced:
return const Tooltip(
return Tooltip(
message: 'Sincronizado',
child: Icon(
Icons.check_circle,
size: 16,
color: Colors.green,
child: _buildIndicator(
const Icon(
Icons.check_circle,
size: 16,
color: Colors.green,
),
),
);
case SyncStatus.error:
return Tooltip(
message: errorMessage ?? 'Error al sincronizar',
child: const Icon(
Icons.error,
size: 16,
color: Colors.red,
child: _buildIndicator(
const Icon(
Icons.error,
size: 16,
color: Colors.red,
),
),
);
}