This commit is contained in:
Phuoc Nguyen
2025-10-10 16:38:07 +07:00
parent e5b247d622
commit b94c158004
177 changed files with 25080 additions and 152 deletions

View File

@@ -0,0 +1,41 @@
import 'package:hive_ce/hive.dart';
import '../models/app_settings_model.dart';
import '../../../../core/constants/storage_constants.dart';
import '../../../../core/constants/app_constants.dart';
/// Settings local data source using Hive
abstract class SettingsLocalDataSource {
Future<AppSettingsModel> getSettings();
Future<void> updateSettings(AppSettingsModel settings);
}
class SettingsLocalDataSourceImpl implements SettingsLocalDataSource {
final Box<AppSettingsModel> box;
SettingsLocalDataSourceImpl(this.box);
@override
Future<AppSettingsModel> getSettings() async {
var settings = box.get(StorageConstants.settingsKey);
// Return default settings if not found
if (settings == null) {
settings = AppSettingsModel(
themeModeString: 'system',
language: AppConstants.defaultLanguage,
currency: AppConstants.defaultCurrency,
taxRate: AppConstants.defaultTaxRate,
storeName: AppConstants.appName,
enableSync: true,
);
await box.put(StorageConstants.settingsKey, settings);
}
return settings;
}
@override
Future<void> updateSettings(AppSettingsModel settings) async {
await box.put(StorageConstants.settingsKey, settings);
}
}

View File

@@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:hive_ce/hive.dart';
import '../../domain/entities/app_settings.dart';
import '../../../../core/constants/storage_constants.dart';
import '../../../../core/constants/app_constants.dart';
part 'app_settings_model.g.dart';
@HiveType(typeId: StorageConstants.appSettingsTypeId)
class AppSettingsModel extends HiveObject {
@HiveField(0)
final String themeModeString;
@HiveField(1)
final String language;
@HiveField(2)
final String currency;
@HiveField(3)
final double taxRate;
@HiveField(4)
final String storeName;
@HiveField(5)
final bool enableSync;
@HiveField(6)
final DateTime? lastSyncAt;
AppSettingsModel({
required this.themeModeString,
required this.language,
required this.currency,
required this.taxRate,
required this.storeName,
required this.enableSync,
this.lastSyncAt,
});
/// Convert to domain entity
AppSettings toEntity() {
ThemeMode themeMode;
switch (themeModeString) {
case 'light':
themeMode = ThemeMode.light;
break;
case 'dark':
themeMode = ThemeMode.dark;
break;
default:
themeMode = ThemeMode.system;
}
return AppSettings(
themeMode: themeMode,
language: language,
currency: currency,
taxRate: taxRate,
storeName: storeName,
enableSync: enableSync,
lastSyncAt: lastSyncAt,
);
}
/// Create from domain entity
factory AppSettingsModel.fromEntity(AppSettings settings) {
String themeModeString;
switch (settings.themeMode) {
case ThemeMode.light:
themeModeString = 'light';
break;
case ThemeMode.dark:
themeModeString = 'dark';
break;
default:
themeModeString = 'system';
}
return AppSettingsModel(
themeModeString: themeModeString,
language: settings.language,
currency: settings.currency,
taxRate: settings.taxRate,
storeName: settings.storeName,
enableSync: settings.enableSync,
lastSyncAt: settings.lastSyncAt,
);
}
/// Create default settings
factory AppSettingsModel.defaultSettings() {
return AppSettingsModel(
themeModeString: 'system',
language: AppConstants.defaultLanguage,
currency: AppConstants.defaultCurrency,
taxRate: AppConstants.defaultTaxRate,
storeName: AppConstants.appName,
enableSync: true,
lastSyncAt: null,
);
}
/// Create from ThemeMode
factory AppSettingsModel.fromThemeMode(ThemeMode mode) {
String themeModeString;
switch (mode) {
case ThemeMode.light:
themeModeString = 'light';
break;
case ThemeMode.dark:
themeModeString = 'dark';
break;
default:
themeModeString = 'system';
}
return AppSettingsModel(
themeModeString: themeModeString,
language: AppConstants.defaultLanguage,
currency: AppConstants.defaultCurrency,
taxRate: AppConstants.defaultTaxRate,
storeName: AppConstants.appName,
enableSync: true,
lastSyncAt: null,
);
}
/// Get ThemeMode from string
ThemeMode get themeMode {
switch (themeModeString) {
case 'light':
return ThemeMode.light;
case 'dark':
return ThemeMode.dark;
default:
return ThemeMode.system;
}
}
/// Create a copy with updated fields
AppSettingsModel copyWith({
String? themeModeString,
String? language,
String? currency,
double? taxRate,
String? storeName,
bool? enableSync,
DateTime? lastSyncAt,
}) {
return AppSettingsModel(
themeModeString: themeModeString ?? this.themeModeString,
language: language ?? this.language,
currency: currency ?? this.currency,
taxRate: taxRate ?? this.taxRate,
storeName: storeName ?? this.storeName,
enableSync: enableSync ?? this.enableSync,
lastSyncAt: lastSyncAt ?? this.lastSyncAt,
);
}
}

View File

@@ -0,0 +1,59 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'app_settings_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class AppSettingsModelAdapter extends TypeAdapter<AppSettingsModel> {
@override
final typeId = 4;
@override
AppSettingsModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return AppSettingsModel(
themeModeString: fields[0] as String,
language: fields[1] as String,
currency: fields[2] as String,
taxRate: (fields[3] as num).toDouble(),
storeName: fields[4] as String,
enableSync: fields[5] as bool,
lastSyncAt: fields[6] as DateTime?,
);
}
@override
void write(BinaryWriter writer, AppSettingsModel obj) {
writer
..writeByte(7)
..writeByte(0)
..write(obj.themeModeString)
..writeByte(1)
..write(obj.language)
..writeByte(2)
..write(obj.currency)
..writeByte(3)
..write(obj.taxRate)
..writeByte(4)
..write(obj.storeName)
..writeByte(5)
..write(obj.enableSync)
..writeByte(6)
..write(obj.lastSyncAt);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AppSettingsModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,36 @@
import 'package:dartz/dartz.dart';
import '../../domain/entities/app_settings.dart';
import '../../domain/repositories/settings_repository.dart';
import '../datasources/settings_local_datasource.dart';
import '../models/app_settings_model.dart';
import '../../../../core/errors/failures.dart';
import '../../../../core/errors/exceptions.dart';
class SettingsRepositoryImpl implements SettingsRepository {
final SettingsLocalDataSource localDataSource;
SettingsRepositoryImpl({
required this.localDataSource,
});
@override
Future<Either<Failure, AppSettings>> getSettings() async {
try {
final settings = await localDataSource.getSettings();
return Right(settings.toEntity());
} on CacheException catch (e) {
return Left(CacheFailure(e.message));
}
}
@override
Future<Either<Failure, void>> updateSettings(AppSettings settings) async {
try {
final model = AppSettingsModel.fromEntity(settings);
await localDataSource.updateSettings(model);
return const Right(null);
} on CacheException catch (e) {
return Left(CacheFailure(e.message));
}
}
}