app scaffold
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
/// 本地持久化。来源:conti-docs/06-local-storage.md。
|
||||
///
|
||||
/// 当前只有 KV 一档。**Drift 数据库暂缓**——骨架阶段没有任何业务表,
|
||||
/// 见 pubspec.yaml 顶部的说明。
|
||||
///
|
||||
/// 边界约定:**token / refresh token 不在这里**——secure storage 归
|
||||
/// `core_auth` 独占(06 §决策表下的说明)。这里存的都是非敏感数据。
|
||||
library;
|
||||
|
||||
export 'src/prefs.dart';
|
||||
export 'src/providers.dart';
|
||||
@@ -0,0 +1,68 @@
|
||||
/// 简单非敏感 KV 的统一封装。来源:06 §决策表第三档。
|
||||
library;
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// 键名常量。
|
||||
///
|
||||
/// **命名约定:用户级的键一律以 [Prefs.userScopedPrefix] 开头。**
|
||||
/// 登出时只清这些,App 级偏好(主题、是否看过引导页)保留——换人登录不该
|
||||
/// 把设备上的通用设置也重置掉。
|
||||
abstract final class PrefKeys {
|
||||
/// 是否看过引导页。App 级,登出保留。
|
||||
static const String onboardingSeen = 'onboarding_seen';
|
||||
|
||||
/// 上次选中的门店 ID。用户级,登出必须清。
|
||||
static const String lastStoreId = '${Prefs.userScopedPrefix}last_store_id';
|
||||
|
||||
/// 是否已同意隐私政策。App 级——同意是设备行为,且埋点/崩溃 SDK 的
|
||||
/// 延迟初始化依赖它(见 13)。
|
||||
static const String privacyPolicyAccepted = 'privacy_policy_accepted';
|
||||
}
|
||||
|
||||
/// `shared_preferences` 的唯一入口。
|
||||
///
|
||||
/// 这里存的都是**非敏感**数据。token / refresh token 走 `core_auth` 的
|
||||
/// secure storage,不允许出现在这里(06 §使用规则)。
|
||||
class Prefs {
|
||||
/// [store] 默认用 `SharedPreferencesAsync`,测试可注入替身。
|
||||
Prefs([SharedPreferencesAsync? store]) : _store = store ?? SharedPreferencesAsync();
|
||||
|
||||
/// 用户级键的前缀。
|
||||
static const String userScopedPrefix = 'u_';
|
||||
|
||||
final SharedPreferencesAsync _store;
|
||||
|
||||
/// 读一个字符串。
|
||||
Future<String?> getString(String key) => _store.getString(key);
|
||||
|
||||
/// 写一个字符串。
|
||||
Future<void> setString(String key, String value) => _store.setString(key, value);
|
||||
|
||||
/// 读一个布尔值,缺省 [defaultValue]。
|
||||
Future<bool> getBool(String key, {bool defaultValue = false}) async =>
|
||||
await _store.getBool(key) ?? defaultValue;
|
||||
|
||||
/// 写一个布尔值。
|
||||
Future<void> setBool(String key, {required bool value}) => _store.setBool(key, value);
|
||||
|
||||
/// 读一个整数。
|
||||
Future<int?> getInt(String key) => _store.getInt(key);
|
||||
|
||||
/// 写一个整数。
|
||||
Future<void> setInt(String key, int value) => _store.setInt(key, value);
|
||||
|
||||
/// 删除一个键。
|
||||
Future<void> remove(String key) => _store.remove(key);
|
||||
|
||||
/// 登出时调用:只清 [userScopedPrefix] 前缀的键,保留 App 级偏好。
|
||||
///
|
||||
/// 用前缀而不是维护一张手写的键名清单——新增用户级配置项时只要遵守命名
|
||||
/// 约定就自动被清掉,手写清单一定会有人忘了加。
|
||||
Future<void> clearUserScoped() async {
|
||||
final Set<String> keys = await _store.getKeys();
|
||||
for (final String key in keys.where((String k) => k.startsWith(userScopedPrefix))) {
|
||||
await _store.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/// core_storage 的 Riverpod 接线。
|
||||
library;
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'prefs.dart';
|
||||
|
||||
/// KV 存储的唯一入口。
|
||||
final Provider<Prefs> prefsProvider = Provider<Prefs>((Ref ref) => Prefs());
|
||||
Reference in New Issue
Block a user