Files
jinzhi/lib/features/assets/data/mock_asset_repository.dart
T

151 lines
4.7 KiB
Dart

import 'dart:convert';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../../common/domain/metal_type.dart';
import '../../../common/storage/preferences_storage.dart';
import '../../../common/storage/storage_keys.dart';
import 'asset_models.dart';
final mockAssetRepositoryProvider = Provider<MockAssetRepository>(
(ref) => MockAssetRepository(ref.watch(preferencesStorageProvider)),
);
class MockAssetRepository {
MockAssetRepository(this._preferences);
static const guestAccountScope = 'guest';
final PreferencesStorage _preferences;
Future<void> _operationTail = Future<void>.value();
static String accountScope({String? userId, String? phone}) {
final normalizedUserId = userId?.trim() ?? '';
if (normalizedUserId.isNotEmpty) return 'id:$normalizedUserId';
final normalizedPhone = phone?.trim() ?? '';
if (normalizedPhone.isNotEmpty) return 'phone:$normalizedPhone';
return guestAccountScope;
}
static String holdingsStorageKey(String accountScope) =>
'$storageJinzhiHoldings:${Uri.encodeComponent(accountScope)}';
static String deletedStorageKey(String accountScope) =>
'$storageJinzhiHoldingsDeleted:${Uri.encodeComponent(accountScope)}';
List<GoldAssetHolding> loadHoldings(String accountScope) {
if (_preferences.getBool(deletedStorageKey(accountScope))) return [];
final encoded = _preferences.getString(holdingsStorageKey(accountScope));
if (encoded == null || encoded.isEmpty) return _seedHoldings();
try {
final decoded = jsonDecode(encoded);
if (decoded is! List) return _seedHoldings();
return [
for (final item in decoded)
GoldAssetHolding.fromJson(Map<String, Object?>.from(item as Map)),
];
} catch (_) {
return _seedHoldings();
}
}
Future<void> saveHoldings(
String accountScope,
List<GoldAssetHolding> holdings,
) async {
final encoded = jsonEncode([
for (final holding in holdings) holding.toJson(),
]);
await _serialize(() async {
await _preferences.setString(holdingsStorageKey(accountScope), encoded);
await _preferences.remove(deletedStorageKey(accountScope));
});
}
Future<void> deleteAccountHoldings(String accountScope) async {
await _serialize(() async {
final scopes = {accountScope, guestAccountScope};
await Future.wait([
for (final scope in scopes) ...[
_preferences.remove(holdingsStorageKey(scope)),
_preferences.setBool(deletedStorageKey(scope), true),
],
// Remove the pre-account-scoping key left by earlier builds.
_preferences.remove(storageJinzhiHoldings),
]);
});
}
Future<T> _serialize<T>(Future<T> Function() operation) {
final result = _operationTail.then((_) => operation());
_operationTail = result.then<void>(
(_) {},
onError: (Object _, StackTrace _) {},
);
return result;
}
List<GoldAssetHolding> _seedHoldings() {
final now = DateTime(2026, 6, 18, 16, 11);
return [
GoldAssetHolding(
id: 'holding_gold_bar_001',
name: '投资金条',
metal: MetalType.gold,
category: AssetCategory.bar,
purity: 0.9999,
purityLabel: '足金9999',
weightGram: 50,
costAmount: 43200,
purchaseDate: DateTime(2025, 10, 12),
channel: '银行',
createdAt: now.subtract(const Duration(days: 249)),
updatedAt: now,
),
GoldAssetHolding(
id: 'holding_gold_ring_001',
name: '素圈戒指',
metal: MetalType.gold,
category: AssetCategory.ring,
purity: 0.999,
purityLabel: '足金999',
weightGram: 8.6,
costAmount: 7820,
purchaseDate: DateTime(2024, 12, 4),
channel: '金店',
createdAt: now.subtract(const Duration(days: 196)),
updatedAt: now,
),
GoldAssetHolding(
id: 'holding_platinum_001',
name: 'PT950 项链',
metal: MetalType.platinum,
category: AssetCategory.platinumPiece,
purity: 0.95,
purityLabel: 'PT950',
weightGram: 12.3,
costAmount: 5200,
purchaseDate: DateTime(2023, 8, 21),
channel: '金店',
createdAt: now.subtract(const Duration(days: 667)),
updatedAt: now,
),
GoldAssetHolding(
id: 'holding_silver_001',
name: '银手镯',
metal: MetalType.silver,
category: AssetCategory.bracelet,
purity: 0.999,
purityLabel: '999银',
weightGram: 31.8,
costAmount: 980,
purchaseDate: DateTime(2024, 4, 7),
channel: '金店',
note: '材料价值偏低',
createdAt: now.subtract(const Duration(days: 802)),
updatedAt: now,
),
];
}
}