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