mirror of
https://github.com/we-promise/sure.git
synced 2026-04-17 19:14:11 +00:00
Fix home page double AppBar inconsistency with settings/more pages (#1250)
* Move debug logs button from Home to Settings page, remove refresh/logout from Home AppBar - Remove Debug Logs, Refresh, and Sign Out buttons from DashboardScreen AppBar - Add Debug Logs ListTile entry in SettingsScreen under app info section - Remove unused _handleLogout method from DashboardScreen - Remove unused log_viewer_screen.dart import from DashboardScreen https://claude.ai/code/session_017XQZdaEwUuRS75tJMcHzB9 * Fix home page double AppBar inconsistency with settings/more pages The DashboardScreen had its own AppBar with a sync success icon, while MainNavigationScreen already provides a shared AppBar (logo + settings) for all tabs. This caused the home page to render a double top bar, inconsistent with the settings and more screens which have no extra AppBar. Remove the dashboard's AppBar and move the sync indicator into the body as an inline banner. https://claude.ai/code/session_0155XXsvt5zKLBpasmdkhPiF * Fix sync success cloud icon not appearing after sync The cloud icon only showed when pending transaction count decreased (local→server uploads). For normal pull-to-refresh syncs that download from server, pendingCount stays at 0 so the icon never triggered. Fix by also detecting when TransactionsProvider.isLoading transitions from true to false (any sync completion), and by triggering the icon directly after successful manual sync instead of showing a redundant snackbar. https://claude.ai/code/session_0155XXsvt5zKLBpasmdkhPiF * Address PR review: fix Timer leak, sync error check, false triggers 1. Timer leak (CodeRabbit): Replace Future.delayed with a cancellable Timer field (_syncSuccessTimer). Cancel existing timer before starting a new one, and clean up in dispose(). 2. Sync error not checked (CodeRabbit): _performManualSync now checks transactionsProvider.error after syncTransactions() returns. Shows error SnackBar on failure instead of false success indicator. 3. False positive triggers (Codex): Remove isLoading transition detection from _onTransactionsChanged since isLoading also toggles for fetchTransactions (non-sync paths). Keep only pendingDecreased for background sync detection; manual sync uses direct call path. https://claude.ai/code/session_0155XXsvt5zKLBpasmdkhPiF * Update mobile/lib/screens/dashboard_screen.dart Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Lazy Bone <89256478+dwvwdv@users.noreply.github.com> --------- Signed-off-by: Lazy Bone <89256478+dwvwdv@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../models/account.dart';
|
||||
@@ -24,6 +25,7 @@ class DashboardScreenState extends State<DashboardScreen> {
|
||||
final LogService _log = LogService.instance;
|
||||
bool _showSyncSuccess = false;
|
||||
int _previousPendingCount = 0;
|
||||
Timer? _syncSuccessTimer;
|
||||
TransactionsProvider? _transactionsProvider;
|
||||
|
||||
// Filter state
|
||||
@@ -51,6 +53,7 @@ class DashboardScreenState extends State<DashboardScreen> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_syncSuccessTimer?.cancel();
|
||||
_transactionsProvider?.removeListener(_onTransactionsChanged);
|
||||
super.dispose();
|
||||
}
|
||||
@@ -60,28 +63,33 @@ class DashboardScreenState extends State<DashboardScreen> {
|
||||
if (transactionsProvider == null || !mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final currentPendingCount = transactionsProvider.pendingCount;
|
||||
|
||||
// If pending count decreased, it means transactions were synced
|
||||
// Show sync success when pending count decreased (local transactions uploaded)
|
||||
if (_previousPendingCount > 0 && currentPendingCount < _previousPendingCount) {
|
||||
setState(() {
|
||||
_showSyncSuccess = true;
|
||||
});
|
||||
|
||||
// Hide the success indicator after 3 seconds
|
||||
Future.delayed(const Duration(seconds: 3), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_showSyncSuccess = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
_showSyncSuccessIndicator();
|
||||
}
|
||||
|
||||
_previousPendingCount = currentPendingCount;
|
||||
}
|
||||
|
||||
void _showSyncSuccessIndicator() {
|
||||
_syncSuccessTimer?.cancel();
|
||||
|
||||
setState(() {
|
||||
_showSyncSuccess = true;
|
||||
});
|
||||
|
||||
_syncSuccessTimer = Timer(const Duration(seconds: 3), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_showSyncSuccess = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadAccounts() async {
|
||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||
final accountsProvider = Provider.of<AccountsProvider>(context, listen: false);
|
||||
@@ -160,19 +168,23 @@ class DashboardScreenState extends State<DashboardScreen> {
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).clearSnackBars();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle, color: Colors.white),
|
||||
SizedBox(width: 12),
|
||||
Text('Sync completed successfully'),
|
||||
],
|
||||
if (transactionsProvider.error != null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
const Icon(Icons.error, color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(child: Text('Sync failed. Please try again.')),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
duration: const Duration(seconds: 3),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
_showSyncSuccessIndicator();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_log.error('DashboardScreen', 'Error in _performManualSync: $e');
|
||||
@@ -343,26 +355,29 @@ class DashboardScreenState extends State<DashboardScreen> {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
if (_showSyncSuccess)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: AnimatedOpacity(
|
||||
opacity: _showSyncSuccess ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: const Icon(
|
||||
Icons.cloud_done,
|
||||
color: Colors.green,
|
||||
size: 28,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
const ConnectivityBanner(),
|
||||
if (_showSyncSuccess)
|
||||
AnimatedOpacity(
|
||||
opacity: _showSyncSuccess ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
color: Colors.green.withValues(alpha: 0.1),
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.cloud_done, color: Colors.green, size: 18),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'Synced',
|
||||
style: TextStyle(color: Colors.green, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Consumer2<AuthProvider, AccountsProvider>(
|
||||
builder: (context, authProvider, accountsProvider, _) {
|
||||
|
||||
Reference in New Issue
Block a user