feat(app): Flutter-клиент — логин, дашборд, потоки, категории, транзакции, правила
Riverpod + go_router с auth-guard, NavigationRail на широком экране и bottom bar на узком. Токены в flutter_secure_storage, на web access живёт в памяти. Интерцептор подставляет токен и делает ровно один refresh на 401. Деньги приходят строками и форматируются через Decimal: парсить их в double значило бы терять копейки ровно там, где бэкенд их бережёт.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Fixed categorical order from the design system's palette (dataviz skill):
|
||||
/// slot 1 blue, slot 2 orange, slot 3 aqua, slot 4 yellow, slot 5 magenta.
|
||||
/// Assigned to entities in this fixed order — never cycled, never by rank.
|
||||
class ChartColors {
|
||||
const ChartColors._();
|
||||
|
||||
static const slot1Blue = Color(0xFF2A78D6);
|
||||
static const slot2Orange = Color(0xFFEB6834);
|
||||
static const slot3Aqua = Color(0xFF1BAF7A);
|
||||
static const slot4Yellow = Color(0xFFEDA100);
|
||||
static const slot5Magenta = Color(0xFFE87BA4);
|
||||
|
||||
/// This app's fixed assignment for cashflow charts.
|
||||
static const income = slot1Blue;
|
||||
static const expense = slot2Orange;
|
||||
static const baseline = slot3Aqua;
|
||||
static const oneOff = slot4Yellow;
|
||||
static const savingsTransfer = slot5Magenta;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
const _prefsKey = 'theme_mode';
|
||||
|
||||
final themeModeProvider = NotifierProvider<ThemeModeController, ThemeMode>(ThemeModeController.new);
|
||||
|
||||
/// Persists the chosen [ThemeMode] to this device via `shared_preferences`.
|
||||
class ThemeModeController extends Notifier<ThemeMode> {
|
||||
@override
|
||||
ThemeMode build() {
|
||||
Future.microtask(_restore);
|
||||
return ThemeMode.system;
|
||||
}
|
||||
|
||||
Future<void> _restore() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final saved = prefs.getString(_prefsKey);
|
||||
state = ThemeMode.values.asNameMap()[saved] ?? ThemeMode.system;
|
||||
}
|
||||
|
||||
Future<void> setMode(ThemeMode mode) async {
|
||||
state = mode;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_prefsKey, mode.name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user