chore: format code

This commit is contained in:
fiatcode 2026-05-04 08:28:05 +07:00
parent 31180f9921
commit 1b3440e2fe
No known key found for this signature in database
7 changed files with 516 additions and 2 deletions

View file

@ -0,0 +1,461 @@
# UI Inconsistencies Analysis - TracPulse
**Date:** Fri May 01 2026
**Status:** Analysis Complete
**Purpose:** Identify and document all UI inconsistencies across the TracPulse Flutter app
---
## Executive Summary
This analysis identifies **15 UI inconsistencies** across the TracPulse application, categorized into:
- **Critical** (4): Impact user experience significantly
- **Moderate** (6): Noticeable visual/interaction inconsistencies
- **Minor** (5): Small polish items
---
## Critical Inconsistencies
### 1. **Inconsistent AppBar Implementations**
**Severity:** Critical
**Location:** Multiple screens
**Issue:**
- `main_screen.dart`: Uses custom header with `Container` (lines 171-226)
- `settings_screen.dart`: Uses standard `AppBar` widget (lines 132-160)
- `status_screen.dart`: Uses standard `AppBar` widget (lines 102-139)
- `permission_screen.dart`: Uses custom header with `Container` (lines 247-271)
**Impact:** Breaks visual consistency and navigation patterns.
**Details:**
```dart
// Main & Permission screens - custom header
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
decoration: const BoxDecoration(
color: Color(0xFF161616),
border: Border(bottom: BorderSide(color: Color(0xFF2a2a2a), width: 1)),
),
// ...
)
// Settings & Status screens - AppBar
AppBar(
backgroundColor: const Color(0xFF161616),
elevation: 0,
leading: IconButton(...),
// ...
)
```
**Recommendation:** Standardize on either AppBar or custom header across all screens.
---
### 2. **Inconsistent Border Radius Values**
**Severity:** Critical
**Location:** All screens
**Issue:** Mixed use of `4` and `3` pixel border radius values throughout the app.
**Examples:**
- `permission_screen.dart` line 118: `borderRadius: BorderRadius.circular(4)` (dialog)
- `permission_screen.dart` line 288: `BorderRadius.all(Radius.circular(4))` (icon container)
- `permission_screen.dart` line 406: `borderRadius: BorderRadius.circular(3)` (granted badge)
- `status_screen.dart` line 224: `borderRadius: BorderRadius.circular(3)` (filter chip)
- `status_screen.dart` line 282: `borderRadius: BorderRadius.circular(3)` (icon container)
**Impact:** Subtle visual inconsistency that degrades polish.
**Recommendation:** Standardize on `4px` border radius globally (align with design system).
---
### 3. **Inconsistent Icon Sizes**
**Severity:** Critical
**Location:** All screens
**Issue:** Icon sizes vary without clear hierarchy or purpose.
**Examples:**
```dart
// Main Screen
Icons.shield, size: 20 // permission_screen header
Icons.gps_fixed, size: 14 // status card
Icons.radio_button_checked, size: 20 // tracking toggle
Icons.arrow_upward, size: 16 // send button
Icons.tune/terminal, size: 16 // nav buttons
// Settings Screen
Icons.arrow_back, size: 20 // back button
// Status Screen
Icons.terminal, size: 18 // title icon
Icons.arrow_back, size: 20 // back button
Icons.refresh, size: 20 // refresh button
Icons.inbox_outlined, size: 48 // empty state
Icons.[log icon], size: 10 // log entry icons
```
**Impact:** Creates visual hierarchy confusion.
**Recommendation:** Define a clear icon size system:
- Extra Large: 48px (empty states, hero elements)
- Large: 24px (primary actions)
- Medium: 20px (navigation, headers)
- Small: 16px (inline actions)
- Extra Small: 12px (badges, chips)
---
### 4. **Inconsistent Padding and Spacing**
**Severity:** Critical
**Location:** All screens
**Issue:** Inconsistent padding values without clear system.
**Examples:**
```dart
// Various padding values used:
padding: EdgeInsets.all(20) // main_screen status card
padding: EdgeInsets.symmetric(horizontal: 20) // main_screen scroll
padding: EdgeInsets.all(16) // permission intro card
padding: EdgeInsets.all(14) // permission items
padding: EdgeInsets.symmetric(horizontal: 14) // settings fields
padding: EdgeInsets.symmetric(horizontal: 16) // status filter bar
padding: EdgeInsets.symmetric(horizontal: 10) // status filter chips
padding: EdgeInsets.only(left: 14, right: 14) // status log entries
```
**Impact:** Reduces visual rhythm and professionalism.
**Recommendation:** Establish spacing system:
- xxs: 4px
- xs: 8px
- sm: 12px
- md: 16px
- lg: 20px
- xl: 24px
- xxl: 32px
---
## Moderate Inconsistencies
### 5. **Inconsistent Text Styles**
**Severity:** Moderate
**Location:** All screens
**Issue:** Text styling lacks systematic hierarchy.
**Examples:**
```dart
// Font sizes used: 9, 10, 11, 12, 13, 14, 16, 18, 48
// Letter spacing: 0, 1, 2, 3
// Font weights: w400, w600, w700
// Headers
fontSize: 18, letterSpacing: 3 // main_screen
fontSize: 16, letterSpacing: 3 // permission_screen
fontSize: 14, letterSpacing: 2 // settings_screen, status_screen
// Body text
fontSize: 13 // various places
fontSize: 12 // various places
fontSize: 11 // various places
```
**Impact:** Reduces readability and visual hierarchy.
**Recommendation:** Create text style system with consistent naming.
---
### 6. **Inconsistent Button Styles**
**Severity:** Moderate
**Location:** Multiple screens
**Issue:** Different button implementations for similar actions.
**Examples:**
```dart
// permission_screen: Custom Material + InkWell (line 512)
Material(
color: _allGranted ? ... : ...,
child: InkWell(onTap: ..., child: Container(...))
)
// main_screen: GestureDetector (line 308)
GestureDetector(
onTap: _toggleTracking,
child: Container(...)
)
// main_screen: OutlinedButton.icon (line 377)
OutlinedButton.icon(
onPressed: ...,
style: OutlinedButton.styleFrom(...),
)
// main_screen: Custom Material + InkWell (line 442)
Material(
color: const Color(0xFF161616),
child: InkWell(...)
)
```
**Impact:** Inconsistent touch feedback and visual states.
**Recommendation:** Standardize on Material + InkWell pattern with consistent ripple effects.
---
### 7. **Inconsistent Empty State Handling**
**Severity:** Moderate
**Location:** `status_screen.dart`
**Issue:** Only Status screen has empty state, but other screens might need it too.
**Current Implementation:** (lines 166-198)
```dart
child: _filteredLogs.isEmpty
? Center(child: Column(...)) // Empty state
: ListView.builder(...)
```
**Impact:** Inconsistent UX when screens have no data.
**Recommendation:** Consider empty states for other screens where applicable.
---
### 8. **Inconsistent Color Opacity Usage**
**Severity:** Moderate
**Location:** All screens
**Issue:** Mixed use of `.withValues(alpha: x)` and color literals.
**Examples:**
```dart
Color(0xFF00bcd4).withValues(alpha: 0.8) // main_screen line 251
Color(0xFF00e676).withValues(alpha: 0.3) // permission_screen line 347
Color(0xFF00e676).withValues(alpha: 0.15) // permission_screen line 359
Color(0xFF00bcd4).withValues(alpha: 0.1) // permission_screen line 430
```
**Impact:** Difficult to maintain consistent transparency levels.
**Recommendation:** Define standard alpha values (0.05, 0.1, 0.15, 0.3, 0.5, 0.6, 0.8).
---
### 9. **Inconsistent Loading/Error State Handling**
**Severity:** Moderate
**Location:** All screens
**Issue:** No consistent loading indicators or error states.
**Observation:**
- No loading spinners shown during async operations
- Error handling relies only on SnackBar
- No retry mechanisms for failed operations
**Recommendation:** Add loading states and error recovery UI.
---
### 10. **Inconsistent Switch Widget Styling**
**Severity:** Moderate
**Location:** `settings_screen.dart` line 386
**Issue:** Switch uses deprecated color properties pattern (though updated to new API).
**Current:**
```dart
Switch(
value: value,
onChanged: onChanged,
activeThumbColor: const Color(0xFF00e676),
activeTrackColor: const Color(0xFF00e676).withValues(alpha: 0.3),
)
```
**Recommendation:** Consider using Material 3 Switch theming for consistency.
---
## Minor Inconsistencies
### 11. **Inconsistent SizedBox Spacing**
**Severity:** Minor
**Location:** All screens
**Issue:** Arbitrary SizedBox heights without clear system.
**Examples:**
```dart
const SizedBox(height: 2) // settings_screen line 374
const SizedBox(height: 4) // permission_screen line 311
const SizedBox(height: 5) // status_screen line 306
const SizedBox(height: 8) // multiple places
const SizedBox(height: 10) // multiple places
const SizedBox(height: 12) // multiple places
// ... and more
```
**Recommendation:** Use spacing system constants instead of literals.
---
### 12. **Inconsistent Container Decoration Pattern**
**Severity:** Minor
**Location:** All screens
**Issue:** Some decorations defined inline, others could use constants.
**Example:**
```dart
// Repeated decoration pattern:
decoration: BoxDecoration(
color: const Color(0xFF161616),
borderRadius: BorderRadius.circular(4),
border: Border.all(color: const Color(0xFF2a2a2a), width: 1),
)
```
**Recommendation:** Create reusable decoration constants.
---
### 13. **Inconsistent Const Usage**
**Severity:** Minor
**Location:** Multiple files
**Issue:** Some widgets marked const, others not (inconsistently).
**Example:**
```dart
// settings_screen line 111
const [
Icon(Icons.check_circle, color: Color(0xFF00e676), size: 18),
// ...
]
```
**Recommendation:** Audit and add const where applicable for performance.
---
### 14. **Inconsistent Dialog Implementation**
**Severity:** Minor
**Location:** `permission_screen.dart` line 112
**Issue:** Only one dialog in app, but pattern not reusable.
**Current:**
```dart
showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => AlertDialog(...)
)
```
**Recommendation:** Create reusable dialog component with consistent styling.
---
### 15. **Inconsistent Animation Usage**
**Severity:** Minor
**Location:** `main_screen.dart` only
**Issue:** Only main screen has animations (pulse effect).
**Current:** (lines 24-36)
```dart
late AnimationController _pulseController;
late Animation<double> _pulseAnimation;
```
**Impact:** Other screens feel static in comparison.
**Recommendation:** Consider subtle animations elsewhere for consistency (e.g., permission granted transitions).
---
## Color System Issues
### Inconsistent Color Definitions
All colors are defined inline with hex literals. Should be centralized:
```dart
// Current usage
const Color(0xFF0d0d0d) // Background
const Color(0xFF161616) // Card background
const Color(0xFF2a2a2a) // Border
const Color(0xFF00bcd4) // Primary (teal)
const Color(0xFF00e676) // Success (green)
const Color(0xFFe0e0e0) // Text primary
const Color(0xFF9e9e9e) // Text secondary
const Color(0xFF616161) // Text disabled
```
**Recommendation:** Create `lib/theme/colors.dart` with named constants.
---
## Priority Matrix
| Priority | Count | Items |
|----------|-------|-------|
| Critical | 4 | AppBar inconsistency, Border radius, Icon sizes, Padding/spacing |
| Moderate | 6 | Text styles, Button styles, Empty states, Color opacity, Loading states, Switch styling |
| Minor | 5 | SizedBox spacing, Container decorations, Const usage, Dialog pattern, Animation usage |
---
## Recommendations Summary
1. **Create Design System** (`lib/theme/`)
- `colors.dart` - Centralized color constants
- `spacing.dart` - Spacing scale
- `typography.dart` - Text style hierarchy
- `decorations.dart` - Reusable decorations
- `dimensions.dart` - Icon sizes, border radius
2. **Standardize Components** (`lib/widgets/`)
- `app_button.dart` - Consistent button component
- `app_header.dart` - Reusable header/appbar
- `app_card.dart` - Standard card container
- `app_dialog.dart` - Consistent dialog styling
3. **Update All Screens**
- Replace inline styles with design system constants
- Standardize component usage
- Add consistent loading/error states
- Ensure const usage for performance
4. **Testing**
- Visual regression testing
- Ensure animations perform smoothly
- Verify touch targets meet accessibility standards
---
## Next Steps
1. **Phase 1: Design System Setup**
- Create theme files
- Define constants
- Document usage
2. **Phase 2: Component Standardization**
- Build reusable widgets
- Update existing screens
- Test interactions
3. **Phase 3: Polish**
- Add missing animations
- Improve empty/error states
- Performance optimization
---
## Notes
- All screens use `fontFamily: 'monospace'` consistently ✓
- Dark theme colors are consistent (good base) ✓
- Material 3 is enabled (`useMaterial3: true`) ✓
- Deprecated APIs have been updated (`.withValues(alpha:)`) ✓
- ZoomPageTransitionsBuilder prevents white flash ✓
---
**End of Analysis**

View file

@ -93,6 +93,9 @@ class BridgeModule : FlutterPlugin, MethodChannel.MethodCallHandler {
"isBatteryOptimizationDisabled" -> { "isBatteryOptimizationDisabled" -> {
result.success(isBatteryOptimizationDisabled()) result.success(isBatteryOptimizationDisabled())
} }
"clearLogs" -> {
clearLogs(result)
}
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
@ -191,6 +194,7 @@ class BridgeModule : FlutterPlugin, MethodChannel.MethodCallHandler {
} }
mainHandler.post { result.success(logs) } mainHandler.post { result.success(logs) }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "fetchLogs failed", e)
mainHandler.post { result.success(emptyList<Map<String, Any>>()) } mainHandler.post { result.success(emptyList<Map<String, Any>>()) }
} }
}.start() }.start()
@ -228,4 +232,23 @@ class BridgeModule : FlutterPlugin, MethodChannel.MethodCallHandler {
false false
} }
} }
private fun clearLogs(result: MethodChannel.Result) {
Thread {
try {
val deleted = runBlocking(Dispatchers.IO) {
val db = context?.let { AppDatabase.getInstance(it) }
if (db != null) {
db.eventLogDao().deleteAll()
} else {
0
}
}
mainHandler.post { result.success(deleted) }
} catch (e: Exception) {
Log.e(TAG, "clearLogs failed", e)
mainHandler.post { result.success(-1) }
}
}.start()
}
} }

View file

@ -42,7 +42,7 @@ import android.util.Log
class LocationTrackingService : Service() { class LocationTrackingService : Service() {
private val binder = LocalBinder() private val binder = LocalBinder()
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val TAG = "LocationTrackingService" private val TAG = "LocationTrackingService"
private lateinit var fusedLocationProvider: FusedLocationProvider private lateinit var fusedLocationProvider: FusedLocationProvider

View file

@ -18,4 +18,7 @@ interface EventLogDao {
@Query("DELETE FROM event_log WHERE timestamp < :beforeTimestamp") @Query("DELETE FROM event_log WHERE timestamp < :beforeTimestamp")
suspend fun deleteOlderThan(beforeTimestamp: Long) suspend fun deleteOlderThan(beforeTimestamp: Long)
@Query("DELETE FROM event_log")
suspend fun deleteAll()
} }

View file

@ -116,4 +116,14 @@ class LocationBridge {
return false; return false;
} }
} }
static Future<int> clearLogs() async {
try {
final result = await _methodChannel.invokeMethod<int>('clearLogs');
return result ?? -1;
} on PlatformException catch (e) {
debugPrint('Failed to clear logs: ${e.message}');
return -1;
}
}
} }

View file

@ -269,4 +269,4 @@ class InfoScreen extends StatelessWidget {
), ),
); );
} }
} }

View file

@ -47,6 +47,15 @@ class _StatusScreenState extends State<StatusScreen> {
} }
} }
Future<void> _clearLogs() async {
final result = await LocationBridge.clearLogs();
if (mounted) {
if (result >= 0) {
await _loadLogs();
}
}
}
String _formatTimestamp(int timestamp) { String _formatTimestamp(int timestamp) {
final dt = DateTime.fromMillisecondsSinceEpoch(timestamp); final dt = DateTime.fromMillisecondsSinceEpoch(timestamp);
final ms = (dt.millisecond / 1000).toStringAsFixed(3).substring(2); final ms = (dt.millisecond / 1000).toStringAsFixed(3).substring(2);
@ -128,6 +137,14 @@ class _StatusScreenState extends State<StatusScreen> {
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
actions: [ actions: [
IconButton(
icon: const Icon(
Icons.delete_outline,
color: Color(0xFF616161),
size: 20,
),
onPressed: _clearLogs,
),
IconButton( IconButton(
icon: const Icon(Icons.refresh, color: Color(0xFF616161), size: 20), icon: const Icon(Icons.refresh, color: Color(0xFF616161), size: 20),
onPressed: _loadLogs, onPressed: _loadLogs,