mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor: app metadata
This commit is contained in:
+3358
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/theme_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
import 'package:immich_mobile/extensions/json_extensions.dart';
|
||||||
|
|
||||||
|
class AppConfig implements MetadataValue {
|
||||||
|
static const String name = 'app-config';
|
||||||
|
|
||||||
|
final ThemeConfig theme;
|
||||||
|
|
||||||
|
const AppConfig({this.theme = const ThemeConfig()});
|
||||||
|
|
||||||
|
factory AppConfig.fromJson(Map<String, Object?> json) {
|
||||||
|
final themeJson = json.nested(ThemeConfig.name);
|
||||||
|
return AppConfig(
|
||||||
|
theme: ThemeConfig(
|
||||||
|
mode: ThemeMode.values.firstWhere(
|
||||||
|
(e) => e.name == themeJson[ThemeConfig.keys.mode],
|
||||||
|
orElse: () => ThemeMode.system,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Object?> toJson() => {
|
||||||
|
ThemeConfig.name: {ThemeConfig.keys.mode: theme.mode.name},
|
||||||
|
};
|
||||||
|
|
||||||
|
AppConfig copyWith({ThemeMode? themeMode}) => AppConfig(theme: ThemeConfig(mode: themeMode ?? theme.mode));
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || (other is AppConfig && other.theme == theme);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => theme.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '$name: { $theme }';
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
|
||||||
|
class _Keys {
|
||||||
|
const _Keys();
|
||||||
|
|
||||||
|
final level = 'level';
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogConfig {
|
||||||
|
static const String name = 'log';
|
||||||
|
|
||||||
|
// ignore: library_private_types_in_public_api
|
||||||
|
static const _Keys keys = _Keys();
|
||||||
|
|
||||||
|
final LogLevel level;
|
||||||
|
|
||||||
|
const LogConfig({this.level = LogLevel.info});
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || (other is LogConfig && other.level == level);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => level.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '$name: {${keys.level}: $level}';
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/config/log_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
import 'package:immich_mobile/extensions/json_extensions.dart';
|
||||||
|
|
||||||
|
class SystemConfig implements MetadataValue {
|
||||||
|
static const String name = 'system-config';
|
||||||
|
|
||||||
|
final LogConfig log;
|
||||||
|
|
||||||
|
const SystemConfig({this.log = const LogConfig()});
|
||||||
|
|
||||||
|
factory SystemConfig.fromJson(Map<String, Object?> json) {
|
||||||
|
final logJson = json.nested(LogConfig.name);
|
||||||
|
return SystemConfig(
|
||||||
|
log: LogConfig(
|
||||||
|
level: LogLevel.values.firstWhere((e) => e.name == logJson[LogConfig.keys.level], orElse: () => LogLevel.info),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Object?> toJson() => {
|
||||||
|
LogConfig.name: {LogConfig.keys.level: log.level.name},
|
||||||
|
};
|
||||||
|
|
||||||
|
SystemConfig copyWith({LogLevel? logLevel}) => SystemConfig(log: LogConfig(level: logLevel ?? log.level));
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || (other is SystemConfig && other.log == log);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => log.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '$name: { $log }';
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class _Keys {
|
||||||
|
const _Keys();
|
||||||
|
|
||||||
|
final mode = 'mode';
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThemeConfig {
|
||||||
|
static const String name = 'theme';
|
||||||
|
// ignore: library_private_types_in_public_api
|
||||||
|
static const _Keys keys = _Keys();
|
||||||
|
|
||||||
|
final ThemeMode mode;
|
||||||
|
|
||||||
|
const ThemeConfig({this.mode = ThemeMode.system});
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || (other is ThemeConfig && other.mode == mode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => mode.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '$name: {${keys.mode}: $mode}';
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
|
||||||
|
class SystemMetadata implements MetadataValue {
|
||||||
|
static const String name = 'system-metadata';
|
||||||
|
|
||||||
|
const SystemMetadata();
|
||||||
|
|
||||||
|
factory SystemMetadata.fromJson(Map<String, Object?> json) => const SystemMetadata();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Object?> toJson() => const {};
|
||||||
|
|
||||||
|
SystemMetadata copyWith() => this;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => other is SystemMetadata;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '$name: {}';
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/config/app_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/system_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata/system_metadata.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
|
||||||
|
enum MetadataKind<T extends MetadataValue> {
|
||||||
|
appConfig<AppConfig>(AppConfig.name, AppConfig.fromJson, AppConfig()),
|
||||||
|
systemConfig<SystemConfig>(SystemConfig.name, SystemConfig.fromJson, SystemConfig()),
|
||||||
|
systemMetadata<SystemMetadata>(SystemMetadata.name, SystemMetadata.fromJson, SystemMetadata());
|
||||||
|
|
||||||
|
final String key;
|
||||||
|
final T Function(Map<String, Object?>) fromJson;
|
||||||
|
final T defaultValue;
|
||||||
|
|
||||||
|
const MetadataKind(this.key, this.fromJson, this.defaultValue);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
abstract class MetadataValue {
|
||||||
|
const MetadataValue();
|
||||||
|
|
||||||
|
Map<String, Object?> toJson();
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ enum StoreKey<T> {
|
|||||||
// user settings from [AppSettingsEnum] below:
|
// user settings from [AppSettingsEnum] below:
|
||||||
loadPreview<bool>._(100),
|
loadPreview<bool>._(100),
|
||||||
loadOriginal<bool>._(101),
|
loadOriginal<bool>._(101),
|
||||||
themeMode<String>._(102),
|
// id 102 (themeMode) moved to user_config.theme-mode
|
||||||
tilesPerRow<int>._(103),
|
tilesPerRow<int>._(103),
|
||||||
dynamicLayout<bool>._(104),
|
dynamicLayout<bool>._(104),
|
||||||
groupAssetsBy<int>._(105),
|
groupAssetsBy<int>._(105),
|
||||||
@@ -35,7 +35,7 @@ enum StoreKey<T> {
|
|||||||
albumThumbnailCacheSize<int>._(112),
|
albumThumbnailCacheSize<int>._(112),
|
||||||
selectedAlbumSortOrder<int>._(113),
|
selectedAlbumSortOrder<int>._(113),
|
||||||
advancedTroubleshooting<bool>._(114),
|
advancedTroubleshooting<bool>._(114),
|
||||||
logLevel<int>._(115),
|
// id 115 (logLevel) moved to app_metadata.log-level
|
||||||
preferRemoteImage<bool>._(116),
|
preferRemoteImage<bool>._(116),
|
||||||
loopVideo<bool>._(117),
|
loopVideo<bool>._(117),
|
||||||
// map related settings
|
// map related settings
|
||||||
|
|||||||
@@ -2,20 +2,20 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
import 'package:immich_mobile/utils/debug_print.dart';
|
import 'package:immich_mobile/utils/debug_print.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
/// Service responsible for handling application logging.
|
/// Service responsible for handling application logging.
|
||||||
///
|
///
|
||||||
/// It listens to Dart's [Logger.root], buffers logs in memory (optionally),
|
/// It listens to Dart's [Logger.root], buffers logs in memory (optionally),
|
||||||
/// writes them to a persistent [ILogRepository], and manages log levels
|
/// writes them to a persistent [LogRepository], and manages log levels via
|
||||||
/// via [IStoreRepository]
|
/// [CachedMetadataRepository].
|
||||||
class LogService {
|
class LogService {
|
||||||
final LogRepository _logRepository;
|
final LogRepository _logRepository;
|
||||||
final DriftStoreRepository _storeRepository;
|
final CachedMetadataRepository _metadataRepository;
|
||||||
|
|
||||||
final List<LogMessage> _msgBuffer = [];
|
final List<LogMessage> _msgBuffer = [];
|
||||||
|
|
||||||
@@ -38,12 +38,12 @@ class LogService {
|
|||||||
|
|
||||||
static Future<LogService> init({
|
static Future<LogService> init({
|
||||||
required LogRepository logRepository,
|
required LogRepository logRepository,
|
||||||
required DriftStoreRepository storeRepository,
|
required CachedMetadataRepository metadataRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
_instance ??= await create(
|
_instance ??= await create(
|
||||||
logRepository: logRepository,
|
logRepository: logRepository,
|
||||||
storeRepository: storeRepository,
|
metadataRepository: metadataRepository,
|
||||||
shouldBuffer: shouldBuffer,
|
shouldBuffer: shouldBuffer,
|
||||||
);
|
);
|
||||||
return _instance!;
|
return _instance!;
|
||||||
@@ -51,17 +51,17 @@ class LogService {
|
|||||||
|
|
||||||
static Future<LogService> create({
|
static Future<LogService> create({
|
||||||
required LogRepository logRepository,
|
required LogRepository logRepository,
|
||||||
required DriftStoreRepository storeRepository,
|
required CachedMetadataRepository metadataRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
final instance = LogService._(logRepository, metadataRepository, shouldBuffer);
|
||||||
await logRepository.truncate(limit: kLogTruncateLimit);
|
await logRepository.truncate(limit: kLogTruncateLimit);
|
||||||
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? LogLevel.info.index;
|
final level = instance._metadataRepository.read(MetadataKind.systemConfig).log.level;
|
||||||
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
|
Logger.root.level = Level.LEVELS.elementAtOrNull(level.index) ?? Level.INFO;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogService._(this._logRepository, this._storeRepository, this._shouldBuffer) {
|
LogService._(this._logRepository, this._metadataRepository, this._shouldBuffer) {
|
||||||
_logSubscription = Logger.root.onRecord.listen(_handleLogRecord);
|
_logSubscription = Logger.root.onRecord.listen(_handleLogRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ class LogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setLogLevel(LogLevel level) async {
|
Future<void> setLogLevel(LogLevel level) async {
|
||||||
await _storeRepository.upsert(StoreKey.logLevel, level.index);
|
await _metadataRepository.update(MetadataKind.systemConfig, (current) => current.copyWith(logLevel: level));
|
||||||
Logger.root.level = level.toLevel();
|
Logger.root.level = level.toLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
extension JsonHelper on Map<String, Object?> {
|
||||||
|
/// Returns the nested map under [key] or an empty const map if the key is absent or the value is not a map
|
||||||
|
Map<String, Object?> nested(String key) => (this[key] as Map<String, Object?>?) ?? const {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
|
class MetadataEntity extends Table with DriftDefaultsMixin {
|
||||||
|
const MetadataEntity();
|
||||||
|
|
||||||
|
TextColumn get key => text()();
|
||||||
|
|
||||||
|
TextColumn get value => text()();
|
||||||
|
|
||||||
|
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {key};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tableName => "metadata";
|
||||||
|
}
|
||||||
@@ -0,0 +1,429 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/metadata.entity.drift.dart'
|
||||||
|
as i1;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/metadata.entity.dart'
|
||||||
|
as i2;
|
||||||
|
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3;
|
||||||
|
|
||||||
|
typedef $$MetadataEntityTableCreateCompanionBuilder =
|
||||||
|
i1.MetadataEntityCompanion Function({
|
||||||
|
required String key,
|
||||||
|
required String value,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
});
|
||||||
|
typedef $$MetadataEntityTableUpdateCompanionBuilder =
|
||||||
|
i1.MetadataEntityCompanion Function({
|
||||||
|
i0.Value<String> key,
|
||||||
|
i0.Value<String> value,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
});
|
||||||
|
|
||||||
|
class $$MetadataEntityTableFilterComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$MetadataEntityTable> {
|
||||||
|
$$MetadataEntityTableFilterComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnFilters<String> get key => $composableBuilder(
|
||||||
|
column: $table.key,
|
||||||
|
builder: (column) => i0.ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
i0.ColumnFilters<String> get value => $composableBuilder(
|
||||||
|
column: $table.value,
|
||||||
|
builder: (column) => i0.ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt,
|
||||||
|
builder: (column) => i0.ColumnFilters(column),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$MetadataEntityTableOrderingComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$MetadataEntityTable> {
|
||||||
|
$$MetadataEntityTableOrderingComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnOrderings<String> get key => $composableBuilder(
|
||||||
|
column: $table.key,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
i0.ColumnOrderings<String> get value => $composableBuilder(
|
||||||
|
column: $table.value,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$MetadataEntityTableAnnotationComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$MetadataEntityTable> {
|
||||||
|
$$MetadataEntityTableAnnotationComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.GeneratedColumn<String> get key =>
|
||||||
|
$composableBuilder(column: $table.key, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<String> get value =>
|
||||||
|
$composableBuilder(column: $table.value, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||||
|
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$MetadataEntityTableTableManager
|
||||||
|
extends
|
||||||
|
i0.RootTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$MetadataEntityTable,
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i1.$$MetadataEntityTableFilterComposer,
|
||||||
|
i1.$$MetadataEntityTableOrderingComposer,
|
||||||
|
i1.$$MetadataEntityTableAnnotationComposer,
|
||||||
|
$$MetadataEntityTableCreateCompanionBuilder,
|
||||||
|
$$MetadataEntityTableUpdateCompanionBuilder,
|
||||||
|
(
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$MetadataEntityTable,
|
||||||
|
i1.MetadataEntityData
|
||||||
|
>,
|
||||||
|
),
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i0.PrefetchHooks Function()
|
||||||
|
> {
|
||||||
|
$$MetadataEntityTableTableManager(
|
||||||
|
i0.GeneratedDatabase db,
|
||||||
|
i1.$MetadataEntityTable table,
|
||||||
|
) : super(
|
||||||
|
i0.TableManagerState(
|
||||||
|
db: db,
|
||||||
|
table: table,
|
||||||
|
createFilteringComposer: () =>
|
||||||
|
i1.$$MetadataEntityTableFilterComposer($db: db, $table: table),
|
||||||
|
createOrderingComposer: () =>
|
||||||
|
i1.$$MetadataEntityTableOrderingComposer($db: db, $table: table),
|
||||||
|
createComputedFieldComposer: () => i1
|
||||||
|
.$$MetadataEntityTableAnnotationComposer($db: db, $table: table),
|
||||||
|
updateCompanionCallback:
|
||||||
|
({
|
||||||
|
i0.Value<String> key = const i0.Value.absent(),
|
||||||
|
i0.Value<String> value = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
}) => i1.MetadataEntityCompanion(
|
||||||
|
key: key,
|
||||||
|
value: value,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
),
|
||||||
|
createCompanionCallback:
|
||||||
|
({
|
||||||
|
required String key,
|
||||||
|
required String value,
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
}) => i1.MetadataEntityCompanion.insert(
|
||||||
|
key: key,
|
||||||
|
value: value,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
),
|
||||||
|
withReferenceMapper: (p0) => p0
|
||||||
|
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
|
||||||
|
.toList(),
|
||||||
|
prefetchHooksCallback: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef $$MetadataEntityTableProcessedTableManager =
|
||||||
|
i0.ProcessedTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$MetadataEntityTable,
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i1.$$MetadataEntityTableFilterComposer,
|
||||||
|
i1.$$MetadataEntityTableOrderingComposer,
|
||||||
|
i1.$$MetadataEntityTableAnnotationComposer,
|
||||||
|
$$MetadataEntityTableCreateCompanionBuilder,
|
||||||
|
$$MetadataEntityTableUpdateCompanionBuilder,
|
||||||
|
(
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$MetadataEntityTable,
|
||||||
|
i1.MetadataEntityData
|
||||||
|
>,
|
||||||
|
),
|
||||||
|
i1.MetadataEntityData,
|
||||||
|
i0.PrefetchHooks Function()
|
||||||
|
>;
|
||||||
|
|
||||||
|
class $MetadataEntityTable extends i2.MetadataEntity
|
||||||
|
with i0.TableInfo<$MetadataEntityTable, i1.MetadataEntityData> {
|
||||||
|
@override
|
||||||
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$MetadataEntityTable(this.attachedDatabase, [this._alias]);
|
||||||
|
static const i0.VerificationMeta _keyMeta = const i0.VerificationMeta('key');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> key = i0.GeneratedColumn<String>(
|
||||||
|
'key',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
);
|
||||||
|
static const i0.VerificationMeta _valueMeta = const i0.VerificationMeta(
|
||||||
|
'value',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> value = i0.GeneratedColumn<String>(
|
||||||
|
'value',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
);
|
||||||
|
static const i0.VerificationMeta _updatedAtMeta = const i0.VerificationMeta(
|
||||||
|
'updatedAt',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<DateTime> updatedAt =
|
||||||
|
i0.GeneratedColumn<DateTime>(
|
||||||
|
'updated_at',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: i0.DriftSqlType.dateTime,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: i3.currentDateAndTime,
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
List<i0.GeneratedColumn> get $columns => [key, value, updatedAt];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'metadata';
|
||||||
|
@override
|
||||||
|
i0.VerificationContext validateIntegrity(
|
||||||
|
i0.Insertable<i1.MetadataEntityData> instance, {
|
||||||
|
bool isInserting = false,
|
||||||
|
}) {
|
||||||
|
final context = i0.VerificationContext();
|
||||||
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('key')) {
|
||||||
|
context.handle(
|
||||||
|
_keyMeta,
|
||||||
|
key.isAcceptableOrUnknown(data['key']!, _keyMeta),
|
||||||
|
);
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_keyMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('value')) {
|
||||||
|
context.handle(
|
||||||
|
_valueMeta,
|
||||||
|
value.isAcceptableOrUnknown(data['value']!, _valueMeta),
|
||||||
|
);
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_valueMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('updated_at')) {
|
||||||
|
context.handle(
|
||||||
|
_updatedAtMeta,
|
||||||
|
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<i0.GeneratedColumn> get $primaryKey => {key};
|
||||||
|
@override
|
||||||
|
i1.MetadataEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return i1.MetadataEntityData(
|
||||||
|
key: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}key'],
|
||||||
|
)!,
|
||||||
|
value: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}value'],
|
||||||
|
)!,
|
||||||
|
updatedAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime,
|
||||||
|
data['${effectivePrefix}updated_at'],
|
||||||
|
)!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$MetadataEntityTable createAlias(String alias) {
|
||||||
|
return $MetadataEntityTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get withoutRowId => true;
|
||||||
|
@override
|
||||||
|
bool get isStrict => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetadataEntityData extends i0.DataClass
|
||||||
|
implements i0.Insertable<i1.MetadataEntityData> {
|
||||||
|
final String key;
|
||||||
|
final String value;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
const MetadataEntityData({
|
||||||
|
required this.key,
|
||||||
|
required this.value,
|
||||||
|
required this.updatedAt,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
map['key'] = i0.Variable<String>(key);
|
||||||
|
map['value'] = i0.Variable<String>(value);
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory MetadataEntityData.fromJson(
|
||||||
|
Map<String, dynamic> json, {
|
||||||
|
i0.ValueSerializer? serializer,
|
||||||
|
}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return MetadataEntityData(
|
||||||
|
key: serializer.fromJson<String>(json['key']),
|
||||||
|
value: serializer.fromJson<String>(json['value']),
|
||||||
|
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'key': serializer.toJson<String>(key),
|
||||||
|
'value': serializer.toJson<String>(value),
|
||||||
|
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.MetadataEntityData copyWith({
|
||||||
|
String? key,
|
||||||
|
String? value,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
}) => i1.MetadataEntityData(
|
||||||
|
key: key ?? this.key,
|
||||||
|
value: value ?? this.value,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
);
|
||||||
|
MetadataEntityData copyWithCompanion(i1.MetadataEntityCompanion data) {
|
||||||
|
return MetadataEntityData(
|
||||||
|
key: data.key.present ? data.key.value : this.key,
|
||||||
|
value: data.value.present ? data.value.value : this.value,
|
||||||
|
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('MetadataEntityData(')
|
||||||
|
..write('key: $key, ')
|
||||||
|
..write('value: $value, ')
|
||||||
|
..write('updatedAt: $updatedAt')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(key, value, updatedAt);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is i1.MetadataEntityData &&
|
||||||
|
other.key == this.key &&
|
||||||
|
other.value == this.value &&
|
||||||
|
other.updatedAt == this.updatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetadataEntityCompanion
|
||||||
|
extends i0.UpdateCompanion<i1.MetadataEntityData> {
|
||||||
|
final i0.Value<String> key;
|
||||||
|
final i0.Value<String> value;
|
||||||
|
final i0.Value<DateTime> updatedAt;
|
||||||
|
const MetadataEntityCompanion({
|
||||||
|
this.key = const i0.Value.absent(),
|
||||||
|
this.value = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
});
|
||||||
|
MetadataEntityCompanion.insert({
|
||||||
|
required String key,
|
||||||
|
required String value,
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
}) : key = i0.Value(key),
|
||||||
|
value = i0.Value(value);
|
||||||
|
static i0.Insertable<i1.MetadataEntityData> custom({
|
||||||
|
i0.Expression<String>? key,
|
||||||
|
i0.Expression<String>? value,
|
||||||
|
i0.Expression<DateTime>? updatedAt,
|
||||||
|
}) {
|
||||||
|
return i0.RawValuesInsertable({
|
||||||
|
if (key != null) 'key': key,
|
||||||
|
if (value != null) 'value': value,
|
||||||
|
if (updatedAt != null) 'updated_at': updatedAt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.MetadataEntityCompanion copyWith({
|
||||||
|
i0.Value<String>? key,
|
||||||
|
i0.Value<String>? value,
|
||||||
|
i0.Value<DateTime>? updatedAt,
|
||||||
|
}) {
|
||||||
|
return i1.MetadataEntityCompanion(
|
||||||
|
key: key ?? this.key,
|
||||||
|
value: value ?? this.value,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
if (key.present) {
|
||||||
|
map['key'] = i0.Variable<String>(key.value);
|
||||||
|
}
|
||||||
|
if (value.present) {
|
||||||
|
map['value'] = i0.Variable<String>(value.value);
|
||||||
|
}
|
||||||
|
if (updatedAt.present) {
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('MetadataEntityCompanion(')
|
||||||
|
..write('key: $key, ')
|
||||||
|
..write('value: $value, ')
|
||||||
|
..write('updatedAt: $updatedAt')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/config/app_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
|
|
||||||
|
class CachedMetadataRepository {
|
||||||
|
final MetadataRepository _repository;
|
||||||
|
final Map<MetadataKind, MetadataValue> _cache = {};
|
||||||
|
|
||||||
|
CachedMetadataRepository._(this._repository);
|
||||||
|
|
||||||
|
static CachedMetadataRepository? _instance;
|
||||||
|
static CachedMetadataRepository get instance {
|
||||||
|
if (_instance == null) {
|
||||||
|
throw UnsupportedError('CachedMetadataRepository not initialized. Call ensureInitialized() first');
|
||||||
|
}
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<CachedMetadataRepository> ensureInitialized({required MetadataRepository repository}) async {
|
||||||
|
if (_instance == null) {
|
||||||
|
final instance = CachedMetadataRepository._(repository);
|
||||||
|
await instance._hydrate();
|
||||||
|
_instance = instance;
|
||||||
|
}
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _hydrate() async {
|
||||||
|
for (final kind in MetadataKind.values) {
|
||||||
|
_cache[kind] = await _repository.get(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T read<T extends MetadataValue>(MetadataKind<T> kind) => (_cache[kind] as T?) ?? kind.defaultValue;
|
||||||
|
|
||||||
|
Future<void> update<T extends MetadataValue>(MetadataKind<T> kind, T Function(T current) mutator) async {
|
||||||
|
final current = read(kind);
|
||||||
|
final updated = mutator(current);
|
||||||
|
if (_cache[kind] == updated) return;
|
||||||
|
await _repository.set(kind, updated);
|
||||||
|
_cache[kind] = updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setAppConfig(AppConfig Function(AppConfig current) mutator) {
|
||||||
|
return update(MetadataKind.appConfig, (c) => mutator.call(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> clear<T extends MetadataValue>(MetadataKind<T> kind) async {
|
||||||
|
await _repository.delete(kind);
|
||||||
|
_cache[kind] = kind.defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<T> watch<T extends MetadataValue>(MetadataKind<T> kind) => _repository.watch(kind);
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/metadata.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/person.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/person.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
||||||
@@ -53,6 +54,7 @@ import 'package:immich_mobile/infrastructure/repositories/db.repository.steps.da
|
|||||||
StoreEntity,
|
StoreEntity,
|
||||||
TrashedLocalAssetEntity,
|
TrashedLocalAssetEntity,
|
||||||
AssetEditEntity,
|
AssetEditEntity,
|
||||||
|
MetadataEntity,
|
||||||
],
|
],
|
||||||
include: {'package:immich_mobile/infrastructure/entities/merged_asset.drift'},
|
include: {'package:immich_mobile/infrastructure/entities/merged_asset.drift'},
|
||||||
)
|
)
|
||||||
@@ -84,7 +86,7 @@ class Drift extends $Drift {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 24;
|
int get schemaVersion => 25;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
@@ -250,6 +252,9 @@ class Drift extends $Drift {
|
|||||||
await customStatement('DROP INDEX IF EXISTS idx_remote_album_owner_id');
|
await customStatement('DROP INDEX IF EXISTS idx_remote_album_owner_id');
|
||||||
await m.alterTable(TableMigration(v24.remoteAlbumEntity));
|
await m.alterTable(TableMigration(v24.remoteAlbumEntity));
|
||||||
},
|
},
|
||||||
|
from24To25: (m, v25) async {
|
||||||
|
await m.createTable(v25.metadata);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -43,9 +43,11 @@ import 'package:immich_mobile/infrastructure/entities/trashed_local_asset.entity
|
|||||||
as i20;
|
as i20;
|
||||||
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.drift.dart'
|
||||||
as i21;
|
as i21;
|
||||||
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/metadata.entity.drift.dart'
|
||||||
as i22;
|
as i22;
|
||||||
import 'package:drift/internal/modular.dart' as i23;
|
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
||||||
|
as i23;
|
||||||
|
import 'package:drift/internal/modular.dart' as i24;
|
||||||
|
|
||||||
abstract class $Drift extends i0.GeneratedDatabase {
|
abstract class $Drift extends i0.GeneratedDatabase {
|
||||||
$Drift(i0.QueryExecutor e) : super(e);
|
$Drift(i0.QueryExecutor e) : super(e);
|
||||||
@@ -89,9 +91,12 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
.$TrashedLocalAssetEntityTable(this);
|
.$TrashedLocalAssetEntityTable(this);
|
||||||
late final i21.$AssetEditEntityTable assetEditEntity = i21
|
late final i21.$AssetEditEntityTable assetEditEntity = i21
|
||||||
.$AssetEditEntityTable(this);
|
.$AssetEditEntityTable(this);
|
||||||
i22.MergedAssetDrift get mergedAssetDrift => i23.ReadDatabaseContainer(
|
late final i22.$MetadataEntityTable metadataEntity = i22.$MetadataEntityTable(
|
||||||
this,
|
this,
|
||||||
).accessor<i22.MergedAssetDrift>(i22.MergedAssetDrift.new);
|
);
|
||||||
|
i23.MergedAssetDrift get mergedAssetDrift => i24.ReadDatabaseContainer(
|
||||||
|
this,
|
||||||
|
).accessor<i23.MergedAssetDrift>(i23.MergedAssetDrift.new);
|
||||||
@override
|
@override
|
||||||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
||||||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
||||||
@@ -129,6 +134,7 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
storeEntity,
|
storeEntity,
|
||||||
trashedLocalAssetEntity,
|
trashedLocalAssetEntity,
|
||||||
assetEditEntity,
|
assetEditEntity,
|
||||||
|
metadataEntity,
|
||||||
i10.idxPartnerSharedWithId,
|
i10.idxPartnerSharedWithId,
|
||||||
i11.idxLatLng,
|
i11.idxLatLng,
|
||||||
i12.idxRemoteAlbumAssetAlbumAsset,
|
i12.idxRemoteAlbumAssetAlbumAsset,
|
||||||
@@ -389,4 +395,6 @@ class $DriftManager {
|
|||||||
);
|
);
|
||||||
i21.$$AssetEditEntityTableTableManager get assetEditEntity =>
|
i21.$$AssetEditEntityTableTableManager get assetEditEntity =>
|
||||||
i21.$$AssetEditEntityTableTableManager(_db, _db.assetEditEntity);
|
i21.$$AssetEditEntityTableTableManager(_db, _db.assetEditEntity);
|
||||||
|
i22.$$MetadataEntityTableTableManager get metadataEntity =>
|
||||||
|
i22.$$MetadataEntityTableTableManager(_db, _db.metadataEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12375,6 +12375,574 @@ class Shape48 extends i0.VersionedTable {
|
|||||||
columnsByName['order']! as i1.GeneratedColumn<int>;
|
columnsByName['order']! as i1.GeneratedColumn<int>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class Schema25 extends i0.VersionedSchema {
|
||||||
|
Schema25({required super.database}) : super(version: 25);
|
||||||
|
@override
|
||||||
|
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||||
|
userEntity,
|
||||||
|
remoteAssetEntity,
|
||||||
|
stackEntity,
|
||||||
|
localAssetEntity,
|
||||||
|
remoteAlbumEntity,
|
||||||
|
localAlbumEntity,
|
||||||
|
localAlbumAssetEntity,
|
||||||
|
idxLocalAlbumAssetAlbumAsset,
|
||||||
|
idxLocalAssetChecksum,
|
||||||
|
idxLocalAssetCloudId,
|
||||||
|
idxStackPrimaryAssetId,
|
||||||
|
idxRemoteAssetOwnerChecksum,
|
||||||
|
uQRemoteAssetsOwnerChecksum,
|
||||||
|
uQRemoteAssetsOwnerLibraryChecksum,
|
||||||
|
idxRemoteAssetChecksum,
|
||||||
|
idxRemoteAssetStackId,
|
||||||
|
idxRemoteAssetLocalDateTimeDay,
|
||||||
|
idxRemoteAssetLocalDateTimeMonth,
|
||||||
|
authUserEntity,
|
||||||
|
userMetadataEntity,
|
||||||
|
partnerEntity,
|
||||||
|
remoteExifEntity,
|
||||||
|
remoteAlbumAssetEntity,
|
||||||
|
remoteAlbumUserEntity,
|
||||||
|
remoteAssetCloudIdEntity,
|
||||||
|
memoryEntity,
|
||||||
|
memoryAssetEntity,
|
||||||
|
personEntity,
|
||||||
|
assetFaceEntity,
|
||||||
|
storeEntity,
|
||||||
|
trashedLocalAssetEntity,
|
||||||
|
assetEditEntity,
|
||||||
|
metadata,
|
||||||
|
idxPartnerSharedWithId,
|
||||||
|
idxLatLng,
|
||||||
|
idxRemoteAlbumAssetAlbumAsset,
|
||||||
|
idxRemoteAssetCloudId,
|
||||||
|
idxPersonOwnerId,
|
||||||
|
idxAssetFacePersonId,
|
||||||
|
idxAssetFaceAssetId,
|
||||||
|
idxTrashedLocalAssetChecksum,
|
||||||
|
idxTrashedLocalAssetAlbum,
|
||||||
|
idxAssetEditAssetId,
|
||||||
|
];
|
||||||
|
late final Shape33 userEntity = Shape33(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'user_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_108,
|
||||||
|
_column_109,
|
||||||
|
_column_110,
|
||||||
|
_column_111,
|
||||||
|
_column_112,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape34 remoteAssetEntity = Shape34(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_108,
|
||||||
|
_column_113,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_116,
|
||||||
|
_column_117,
|
||||||
|
_column_118,
|
||||||
|
_column_107,
|
||||||
|
_column_119,
|
||||||
|
_column_120,
|
||||||
|
_column_121,
|
||||||
|
_column_122,
|
||||||
|
_column_123,
|
||||||
|
_column_124,
|
||||||
|
_column_125,
|
||||||
|
_column_126,
|
||||||
|
_column_127,
|
||||||
|
_column_128,
|
||||||
|
_column_129,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape35 stackEntity = Shape35(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'stack_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_121,
|
||||||
|
_column_130,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape36 localAssetEntity = Shape36(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'local_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_108,
|
||||||
|
_column_113,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_116,
|
||||||
|
_column_117,
|
||||||
|
_column_118,
|
||||||
|
_column_107,
|
||||||
|
_column_131,
|
||||||
|
_column_120,
|
||||||
|
_column_132,
|
||||||
|
_column_133,
|
||||||
|
_column_134,
|
||||||
|
_column_135,
|
||||||
|
_column_136,
|
||||||
|
_column_137,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape48 remoteAlbumEntity = Shape48(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_album_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_108,
|
||||||
|
_column_138,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_139,
|
||||||
|
_column_140,
|
||||||
|
_column_141,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape38 localAlbumEntity = Shape38(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'local_album_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_108,
|
||||||
|
_column_115,
|
||||||
|
_column_142,
|
||||||
|
_column_143,
|
||||||
|
_column_144,
|
||||||
|
_column_145,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape39 localAlbumAssetEntity = Shape39(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'local_album_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(asset_id, album_id)'],
|
||||||
|
columns: [_column_146, _column_147, _column_145],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
final i1.Index idxLocalAlbumAssetAlbumAsset = i1.Index(
|
||||||
|
'idx_local_album_asset_album_asset',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxLocalAssetChecksum = i1.Index(
|
||||||
|
'idx_local_asset_checksum',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)',
|
||||||
|
);
|
||||||
|
final i1.Index idxLocalAssetCloudId = i1.Index(
|
||||||
|
'idx_local_asset_cloud_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxStackPrimaryAssetId = i1.Index(
|
||||||
|
'idx_stack_primary_asset_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetOwnerChecksum = i1.Index(
|
||||||
|
'idx_remote_asset_owner_checksum',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)',
|
||||||
|
);
|
||||||
|
final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index(
|
||||||
|
'UQ_remote_assets_owner_checksum',
|
||||||
|
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)',
|
||||||
|
);
|
||||||
|
final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index(
|
||||||
|
'UQ_remote_assets_owner_library_checksum',
|
||||||
|
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetChecksum = i1.Index(
|
||||||
|
'idx_remote_asset_checksum',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetStackId = i1.Index(
|
||||||
|
'idx_remote_asset_stack_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetLocalDateTimeDay = i1.Index(
|
||||||
|
'idx_remote_asset_local_date_time_day',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_day ON remote_asset_entity (STRFTIME(\'%Y-%m-%d\', local_date_time))',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetLocalDateTimeMonth = i1.Index(
|
||||||
|
'idx_remote_asset_local_date_time_month',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_month ON remote_asset_entity (STRFTIME(\'%Y-%m\', local_date_time))',
|
||||||
|
);
|
||||||
|
late final Shape40 authUserEntity = Shape40(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'auth_user_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_108,
|
||||||
|
_column_109,
|
||||||
|
_column_148,
|
||||||
|
_column_110,
|
||||||
|
_column_111,
|
||||||
|
_column_149,
|
||||||
|
_column_150,
|
||||||
|
_column_151,
|
||||||
|
_column_152,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape4 userMetadataEntity = Shape4(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'user_metadata_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(user_id, "key")'],
|
||||||
|
columns: [_column_153, _column_154, _column_155],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape41 partnerEntity = Shape41(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'partner_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'],
|
||||||
|
columns: [_column_156, _column_157, _column_158],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape42 remoteExifEntity = Shape42(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_exif_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(asset_id)'],
|
||||||
|
columns: [
|
||||||
|
_column_159,
|
||||||
|
_column_160,
|
||||||
|
_column_161,
|
||||||
|
_column_162,
|
||||||
|
_column_163,
|
||||||
|
_column_164,
|
||||||
|
_column_117,
|
||||||
|
_column_116,
|
||||||
|
_column_165,
|
||||||
|
_column_166,
|
||||||
|
_column_167,
|
||||||
|
_column_168,
|
||||||
|
_column_135,
|
||||||
|
_column_136,
|
||||||
|
_column_169,
|
||||||
|
_column_170,
|
||||||
|
_column_171,
|
||||||
|
_column_172,
|
||||||
|
_column_173,
|
||||||
|
_column_174,
|
||||||
|
_column_175,
|
||||||
|
_column_176,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape7 remoteAlbumAssetEntity = Shape7(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_album_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(asset_id, album_id)'],
|
||||||
|
columns: [_column_159, _column_177],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape10 remoteAlbumUserEntity = Shape10(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_album_user_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(album_id, user_id)'],
|
||||||
|
columns: [_column_177, _column_153, _column_178],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape43 remoteAssetCloudIdEntity = Shape43(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'remote_asset_cloud_id_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(asset_id)'],
|
||||||
|
columns: [
|
||||||
|
_column_159,
|
||||||
|
_column_179,
|
||||||
|
_column_180,
|
||||||
|
_column_134,
|
||||||
|
_column_135,
|
||||||
|
_column_136,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape44 memoryEntity = Shape44(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'memory_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_124,
|
||||||
|
_column_121,
|
||||||
|
_column_113,
|
||||||
|
_column_181,
|
||||||
|
_column_182,
|
||||||
|
_column_183,
|
||||||
|
_column_184,
|
||||||
|
_column_185,
|
||||||
|
_column_186,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape12 memoryAssetEntity = Shape12(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'memory_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'],
|
||||||
|
columns: [_column_159, _column_187],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape45 personEntity = Shape45(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'person_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_121,
|
||||||
|
_column_108,
|
||||||
|
_column_188,
|
||||||
|
_column_189,
|
||||||
|
_column_190,
|
||||||
|
_column_191,
|
||||||
|
_column_192,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape46 assetFaceEntity = Shape46(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'asset_face_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_159,
|
||||||
|
_column_193,
|
||||||
|
_column_194,
|
||||||
|
_column_195,
|
||||||
|
_column_196,
|
||||||
|
_column_197,
|
||||||
|
_column_198,
|
||||||
|
_column_199,
|
||||||
|
_column_200,
|
||||||
|
_column_201,
|
||||||
|
_column_124,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape18 storeEntity = Shape18(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'store_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [_column_202, _column_203, _column_204],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape47 trashedLocalAssetEntity = Shape47(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'trashed_local_asset_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id, album_id)'],
|
||||||
|
columns: [
|
||||||
|
_column_108,
|
||||||
|
_column_113,
|
||||||
|
_column_114,
|
||||||
|
_column_115,
|
||||||
|
_column_116,
|
||||||
|
_column_117,
|
||||||
|
_column_118,
|
||||||
|
_column_107,
|
||||||
|
_column_205,
|
||||||
|
_column_131,
|
||||||
|
_column_120,
|
||||||
|
_column_132,
|
||||||
|
_column_206,
|
||||||
|
_column_137,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape32 assetEditEntity = Shape32(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'asset_edit_entity',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY(id)'],
|
||||||
|
columns: [
|
||||||
|
_column_107,
|
||||||
|
_column_159,
|
||||||
|
_column_207,
|
||||||
|
_column_208,
|
||||||
|
_column_209,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
late final Shape49 metadata = Shape49(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'metadata',
|
||||||
|
withoutRowId: true,
|
||||||
|
isStrict: true,
|
||||||
|
tableConstraints: ['PRIMARY KEY("key")'],
|
||||||
|
columns: [_column_210, _column_211, _column_115],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null,
|
||||||
|
);
|
||||||
|
final i1.Index idxPartnerSharedWithId = i1.Index(
|
||||||
|
'idx_partner_shared_with_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxLatLng = i1.Index(
|
||||||
|
'idx_lat_lng',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAlbumAssetAlbumAsset = i1.Index(
|
||||||
|
'idx_remote_album_asset_album_asset',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxRemoteAssetCloudId = i1.Index(
|
||||||
|
'idx_remote_asset_cloud_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxPersonOwnerId = i1.Index(
|
||||||
|
'idx_person_owner_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxAssetFacePersonId = i1.Index(
|
||||||
|
'idx_asset_face_person_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxAssetFaceAssetId = i1.Index(
|
||||||
|
'idx_asset_face_asset_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxTrashedLocalAssetChecksum = i1.Index(
|
||||||
|
'idx_trashed_local_asset_checksum',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)',
|
||||||
|
);
|
||||||
|
final i1.Index idxTrashedLocalAssetAlbum = i1.Index(
|
||||||
|
'idx_trashed_local_asset_album',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)',
|
||||||
|
);
|
||||||
|
final i1.Index idxAssetEditAssetId = i1.Index(
|
||||||
|
'idx_asset_edit_asset_id',
|
||||||
|
'CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Shape49 extends i0.VersionedTable {
|
||||||
|
Shape49({required super.source, required super.alias}) : super.aliased();
|
||||||
|
i1.GeneratedColumn<String> get key =>
|
||||||
|
columnsByName['key']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get value =>
|
||||||
|
columnsByName['value']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get updatedAt =>
|
||||||
|
columnsByName['updated_at']! as i1.GeneratedColumn<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.GeneratedColumn<String> _column_210(String aliasedName) =>
|
||||||
|
i1.GeneratedColumn<String>(
|
||||||
|
'key',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: i1.DriftSqlType.string,
|
||||||
|
$customConstraints: 'NOT NULL',
|
||||||
|
);
|
||||||
|
i1.GeneratedColumn<String> _column_211(String aliasedName) =>
|
||||||
|
i1.GeneratedColumn<String>(
|
||||||
|
'value',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: i1.DriftSqlType.string,
|
||||||
|
$customConstraints: 'NOT NULL',
|
||||||
|
);
|
||||||
i0.MigrationStepWithVersion migrationSteps({
|
i0.MigrationStepWithVersion migrationSteps({
|
||||||
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
||||||
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||||
@@ -12399,6 +12967,7 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
required Future<void> Function(i1.Migrator m, Schema22 schema) from21To22,
|
required Future<void> Function(i1.Migrator m, Schema22 schema) from21To22,
|
||||||
required Future<void> Function(i1.Migrator m, Schema23 schema) from22To23,
|
required Future<void> Function(i1.Migrator m, Schema23 schema) from22To23,
|
||||||
required Future<void> Function(i1.Migrator m, Schema24 schema) from23To24,
|
required Future<void> Function(i1.Migrator m, Schema24 schema) from23To24,
|
||||||
|
required Future<void> Function(i1.Migrator m, Schema25 schema) from24To25,
|
||||||
}) {
|
}) {
|
||||||
return (currentVersion, database) async {
|
return (currentVersion, database) async {
|
||||||
switch (currentVersion) {
|
switch (currentVersion) {
|
||||||
@@ -12517,6 +13086,11 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
final migrator = i1.Migrator(database, schema);
|
final migrator = i1.Migrator(database, schema);
|
||||||
await from23To24(migrator, schema);
|
await from23To24(migrator, schema);
|
||||||
return 24;
|
return 24;
|
||||||
|
case 24:
|
||||||
|
final schema = Schema25(database: database);
|
||||||
|
final migrator = i1.Migrator(database, schema);
|
||||||
|
await from24To25(migrator, schema);
|
||||||
|
return 25;
|
||||||
default:
|
default:
|
||||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||||
}
|
}
|
||||||
@@ -12547,6 +13121,7 @@ i1.OnUpgrade stepByStep({
|
|||||||
required Future<void> Function(i1.Migrator m, Schema22 schema) from21To22,
|
required Future<void> Function(i1.Migrator m, Schema22 schema) from21To22,
|
||||||
required Future<void> Function(i1.Migrator m, Schema23 schema) from22To23,
|
required Future<void> Function(i1.Migrator m, Schema23 schema) from22To23,
|
||||||
required Future<void> Function(i1.Migrator m, Schema24 schema) from23To24,
|
required Future<void> Function(i1.Migrator m, Schema24 schema) from23To24,
|
||||||
|
required Future<void> Function(i1.Migrator m, Schema25 schema) from24To25,
|
||||||
}) => i0.VersionedSchema.stepByStepHelper(
|
}) => i0.VersionedSchema.stepByStepHelper(
|
||||||
step: migrationSteps(
|
step: migrationSteps(
|
||||||
from1To2: from1To2,
|
from1To2: from1To2,
|
||||||
@@ -12572,5 +13147,6 @@ i1.OnUpgrade stepByStep({
|
|||||||
from21To22: from21To22,
|
from21To22: from21To22,
|
||||||
from22To23: from22To23,
|
from22To23: from22To23,
|
||||||
from23To24: from23To24,
|
from23To24: from23To24,
|
||||||
|
from24To25: from24To25,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_value.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/metadata.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
|
class MetadataRepository extends DriftDatabaseRepository {
|
||||||
|
final Drift _db;
|
||||||
|
|
||||||
|
const MetadataRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
Future<T> get<T extends MetadataValue>(MetadataKind<T> kind) async {
|
||||||
|
final row = await (_db.select(_db.metadataEntity)..where((t) => t.key.equals(kind.key))).getSingleOrNull();
|
||||||
|
return _toValue(kind, row) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> set<T extends MetadataValue>(MetadataKind<T> kind, T value) async {
|
||||||
|
await _db
|
||||||
|
.into(_db.metadataEntity)
|
||||||
|
.insertOnConflictUpdate(
|
||||||
|
MetadataEntityCompanion.insert(
|
||||||
|
key: kind.key,
|
||||||
|
value: jsonEncode(value.toJson()),
|
||||||
|
updatedAt: Value(DateTime.now()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> delete<T extends MetadataValue>(MetadataKind<T> kind) async {
|
||||||
|
await (_db.delete(_db.metadataEntity)..where((t) => t.key.equals(kind.key))).go();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<T> watch<T extends MetadataValue>(MetadataKind<T> kind) {
|
||||||
|
return (_db.select(
|
||||||
|
_db.metadataEntity,
|
||||||
|
)..where((t) => t.key.equals(kind.key))).watchSingleOrNull().map((row) => _toValue(kind, row) as T);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetadataValue _toValue(MetadataKind kind, MetadataEntityData? row) =>
|
||||||
|
row == null ? kind.defaultValue : kind.fromJson(jsonDecode(row.value) as Map<String, Object?>);
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@ void main() async {
|
|||||||
await initApp();
|
await initApp();
|
||||||
// Warm-up isolate pool for worker manager
|
// Warm-up isolate pool for worker manager
|
||||||
await workerManagerPatch.init(dynamicSpawning: true, isolatesCount: max(Platform.numberOfProcessors - 1, 5));
|
await workerManagerPatch.init(dynamicSpawning: true, isolatesCount: max(Platform.numberOfProcessors - 1, 5));
|
||||||
await migrateDatabaseIfNeeded();
|
await migrateDatabaseIfNeeded(drift);
|
||||||
|
|
||||||
runApp(ProviderScope(overrides: [driftProvider.overrideWith(driftOverride(drift))], child: const MainWidget()));
|
runApp(ProviderScope(overrides: [driftProvider.overrideWith(driftOverride(drift))], child: const MainWidget()));
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/app_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/system_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata/system_metadata.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
|
|
||||||
|
final metadataProvider = Provider.autoDispose<CachedMetadataRepository>((_) => CachedMetadataRepository.instance);
|
||||||
|
|
||||||
|
final appConfigProvider = Provider.autoDispose<AppConfig>((ref) {
|
||||||
|
final subscription = ref.watch(metadataProvider).watch(MetadataKind.appConfig).listen((event) {
|
||||||
|
ref.state = event;
|
||||||
|
});
|
||||||
|
ref.onDispose(subscription.cancel);
|
||||||
|
return ref.watch(metadataProvider).read(MetadataKind.appConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
final systemConfigProvider = Provider.autoDispose<SystemConfig>((ref) {
|
||||||
|
final subscription = ref.watch(metadataProvider).watch(MetadataKind.systemConfig).listen((event) {
|
||||||
|
ref.state = event;
|
||||||
|
});
|
||||||
|
ref.onDispose(subscription.cancel);
|
||||||
|
return ref.watch(metadataProvider).read(MetadataKind.systemConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
final systemMetadataProvider = Provider.autoDispose<SystemMetadata>((ref) {
|
||||||
|
final subscription = ref.watch(metadataProvider).watch(MetadataKind.systemMetadata).listen((event) {
|
||||||
|
ref.state = event;
|
||||||
|
});
|
||||||
|
ref.onDispose(subscription.cancel);
|
||||||
|
return ref.watch(metadataProvider).read(MetadataKind.systemMetadata);
|
||||||
|
});
|
||||||
@@ -1,27 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/constants/colors.dart';
|
import 'package:immich_mobile/constants/colors.dart';
|
||||||
import 'package:immich_mobile/theme/color_scheme.dart';
|
|
||||||
import 'package:immich_mobile/theme/theme_data.dart';
|
|
||||||
import 'package:immich_mobile/theme/dynamic_theme.dart';
|
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||||
|
import 'package:immich_mobile/theme/color_scheme.dart';
|
||||||
|
import 'package:immich_mobile/theme/dynamic_theme.dart';
|
||||||
|
import 'package:immich_mobile/theme/theme_data.dart';
|
||||||
import 'package:immich_mobile/utils/debug_print.dart';
|
import 'package:immich_mobile/utils/debug_print.dart';
|
||||||
|
|
||||||
final immichThemeModeProvider = StateProvider<ThemeMode>((ref) {
|
final immichThemeModeProvider = StateProvider<ThemeMode>((ref) => ref.read(appConfigProvider).theme.mode);
|
||||||
final themeMode = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.themeMode);
|
|
||||||
|
|
||||||
dPrint(() => "Current themeMode $themeMode");
|
|
||||||
|
|
||||||
if (themeMode == ThemeMode.light.name) {
|
|
||||||
return ThemeMode.light;
|
|
||||||
} else if (themeMode == ThemeMode.dark.name) {
|
|
||||||
return ThemeMode.dark;
|
|
||||||
} else {
|
|
||||||
return ThemeMode.system;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final immichThemePresetProvider = StateProvider<ImmichColorPreset>((ref) {
|
final immichThemePresetProvider = StateProvider<ImmichColorPreset>((ref) {
|
||||||
final appSettingsProvider = ref.watch(appSettingsServiceProvider);
|
final appSettingsProvider = ref.watch(appSettingsServiceProvider);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:immich_mobile/entities/store.entity.dart';
|
|||||||
enum AppSettingsEnum<T> {
|
enum AppSettingsEnum<T> {
|
||||||
loadPreview<bool>(StoreKey.loadPreview, "loadPreview", true),
|
loadPreview<bool>(StoreKey.loadPreview, "loadPreview", true),
|
||||||
loadOriginal<bool>(StoreKey.loadOriginal, "loadOriginal", false),
|
loadOriginal<bool>(StoreKey.loadOriginal, "loadOriginal", false),
|
||||||
themeMode<String>(StoreKey.themeMode, "themeMode", "system"), // "light","dark","system"
|
|
||||||
primaryColor<String>(StoreKey.primaryColor, "primaryColor", defaultColorPresetName),
|
primaryColor<String>(StoreKey.primaryColor, "primaryColor", defaultColorPresetName),
|
||||||
dynamicTheme<bool>(StoreKey.dynamicTheme, "dynamicTheme", false),
|
dynamicTheme<bool>(StoreKey.dynamicTheme, "dynamicTheme", false),
|
||||||
colorfulInterface<bool>(StoreKey.colorfulInterface, "colorfulInterface", true),
|
colorfulInterface<bool>(StoreKey.colorfulInterface, "colorfulInterface", true),
|
||||||
@@ -30,7 +29,6 @@ enum AppSettingsEnum<T> {
|
|||||||
selectedAlbumSortOrder<int>(StoreKey.selectedAlbumSortOrder, "selectedAlbumSortOrder", 2),
|
selectedAlbumSortOrder<int>(StoreKey.selectedAlbumSortOrder, "selectedAlbumSortOrder", 2),
|
||||||
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
|
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
|
||||||
manageLocalMediaAndroid<bool>(StoreKey.manageLocalMediaAndroid, null, false),
|
manageLocalMediaAndroid<bool>(StoreKey.manageLocalMediaAndroid, null, false),
|
||||||
logLevel<int>(StoreKey.logLevel, null, 5), // Level.INFO = 5
|
|
||||||
preferRemoteImage<bool>(StoreKey.preferRemoteImage, null, false),
|
preferRemoteImage<bool>(StoreKey.preferRemoteImage, null, false),
|
||||||
loopVideo<bool>(StoreKey.loopVideo, "loopVideo", true),
|
loopVideo<bool>(StoreKey.loopVideo, "loopVideo", true),
|
||||||
loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, "loadOriginalVideo", false),
|
loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, "loadOriginalVideo", false),
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/utils/background_sync.dart';
|
import 'package:immich_mobile/domain/utils/background_sync.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||||
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
||||||
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/auth.repository.dart';
|
import 'package:immich_mobile/repositories/auth.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/auth_api.repository.dart';
|
import 'package:immich_mobile/repositories/auth_api.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
@@ -26,6 +29,7 @@ final authServiceProvider = Provider(
|
|||||||
ref.watch(networkServiceProvider),
|
ref.watch(networkServiceProvider),
|
||||||
ref.watch(backgroundSyncProvider),
|
ref.watch(backgroundSyncProvider),
|
||||||
ref.watch(appSettingsServiceProvider),
|
ref.watch(appSettingsServiceProvider),
|
||||||
|
ref.watch(metadataProvider),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -36,6 +40,7 @@ class AuthService {
|
|||||||
final NetworkService _networkService;
|
final NetworkService _networkService;
|
||||||
final BackgroundSyncManager _backgroundSyncManager;
|
final BackgroundSyncManager _backgroundSyncManager;
|
||||||
final AppSettingsService _appSettingsService;
|
final AppSettingsService _appSettingsService;
|
||||||
|
final CachedMetadataRepository _metadataRepository;
|
||||||
final _log = Logger("AuthService");
|
final _log = Logger("AuthService");
|
||||||
|
|
||||||
AuthService(
|
AuthService(
|
||||||
@@ -45,6 +50,7 @@ class AuthService {
|
|||||||
this._networkService,
|
this._networkService,
|
||||||
this._backgroundSyncManager,
|
this._backgroundSyncManager,
|
||||||
this._appSettingsService,
|
this._appSettingsService,
|
||||||
|
this._metadataRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Validates the provided server URL by resolving and setting the endpoint.
|
/// Validates the provided server URL by resolving and setting the endpoint.
|
||||||
@@ -128,6 +134,7 @@ class AuthService {
|
|||||||
Store.delete(StoreKey.preferredWifiName),
|
Store.delete(StoreKey.preferredWifiName),
|
||||||
Store.delete(StoreKey.localEndpoint),
|
Store.delete(StoreKey.localEndpoint),
|
||||||
Store.delete(StoreKey.externalEndpointList),
|
Store.delete(StoreKey.externalEndpointList),
|
||||||
|
_metadataRepository.clear(MetadataKind.appConfig),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import 'package:immich_mobile/constants/constants.dart';
|
|||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
@@ -48,9 +50,13 @@ abstract final class Bootstrap {
|
|||||||
|
|
||||||
await StoreService.init(storeRepository: storeRepo, listenUpdates: listenStoreUpdates);
|
await StoreService.init(storeRepository: storeRepo, listenUpdates: listenStoreUpdates);
|
||||||
|
|
||||||
|
final cachedMetadataRepository = await CachedMetadataRepository.ensureInitialized(
|
||||||
|
repository: MetadataRepository(drift),
|
||||||
|
);
|
||||||
|
|
||||||
await LogService.init(
|
await LogService.init(
|
||||||
logRepository: LogRepository(logDb),
|
logRepository: LogRepository(logDb),
|
||||||
storeRepository: storeRepo,
|
metadataRepository: cachedMetadataRepository,
|
||||||
shouldBuffer: shouldBufferLogs,
|
shouldBuffer: shouldBufferLogs,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||||
|
|
||||||
ValueNotifier<T> useAppSettingsState<T>(AppSettingsEnum<T> key) {
|
ValueNotifier<T> useAppSettingsState<T>(AppSettingsEnum<T> key) {
|
||||||
final notifier = useState<T>(Store.get(key.storeKey, key.defaultValue));
|
final notifier = useState<T>(Store.get(key.storeKey, key.defaultValue));
|
||||||
|
|||||||
@@ -1,25 +1,80 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
|
|
||||||
const int targetVersion = 25;
|
const int targetVersion = 26;
|
||||||
|
|
||||||
Future<void> migrateDatabaseIfNeeded() async {
|
Future<void> migrateDatabaseIfNeeded(Drift drift) async {
|
||||||
final int version = Store.get(StoreKey.version, targetVersion);
|
final int version = Store.get(StoreKey.version, targetVersion);
|
||||||
|
|
||||||
if (version < 25) {
|
if (version < 25) {
|
||||||
final accessToken = Store.tryGet(StoreKey.accessToken);
|
await _migrateTo25();
|
||||||
if (accessToken != null && accessToken.isNotEmpty) {
|
}
|
||||||
final serverUrls = ApiService.getServerUrls();
|
|
||||||
if (serverUrls.isNotEmpty) {
|
if (version < 26) {
|
||||||
await NetworkRepository.setHeaders(ApiService.getRequestHeaders(), serverUrls, token: accessToken);
|
await _migrateTo26(drift);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Store.put(StoreKey.version, targetVersion);
|
await Store.put(StoreKey.version, targetVersion);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _migrateTo25() async {
|
||||||
|
final accessToken = Store.tryGet(StoreKey.accessToken);
|
||||||
|
if (accessToken == null || accessToken.isEmpty) return;
|
||||||
|
|
||||||
|
final serverUrls = ApiService.getServerUrls();
|
||||||
|
if (serverUrls.isEmpty) return;
|
||||||
|
|
||||||
|
await NetworkRepository.setHeaders(ApiService.getRequestHeaders(), serverUrls, token: accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _migrateTo26(Drift drift) async {
|
||||||
|
const int themeModeKey = 102;
|
||||||
|
const int logLevelKey = 115;
|
||||||
|
|
||||||
|
final cache = CachedMetadataRepository.instance;
|
||||||
|
final migrated = <int>[];
|
||||||
|
|
||||||
|
final themeMode = await _readLegacyStoreString(drift, themeModeKey);
|
||||||
|
if (themeMode != null) {
|
||||||
|
final mode = ThemeMode.values.firstWhere((m) => m.name == themeMode, orElse: () => ThemeMode.system);
|
||||||
|
await cache.update(MetadataKind.appConfig, (current) => current.copyWith(themeMode: mode));
|
||||||
|
migrated.add(themeModeKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
final logLevelIndex = await _readLegacyStoreInt(drift, logLevelKey);
|
||||||
|
if (logLevelIndex != null) {
|
||||||
|
final logLevel = LogLevel.values.elementAtOrNull(logLevelIndex) ?? LogLevel.info;
|
||||||
|
await cache.update(MetadataKind.systemConfig, (current) => current.copyWith(logLevel: logLevel));
|
||||||
|
await LogService.I.setLogLevel(logLevel);
|
||||||
|
migrated.add(logLevelKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _deleteLegacyStoreRows(drift, migrated);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> _readLegacyStoreString(Drift drift, int id) async {
|
||||||
|
final row = await (drift.storeEntity.select()..where((t) => t.id.equals(id))).getSingleOrNull();
|
||||||
|
return row?.stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int?> _readLegacyStoreInt(Drift drift, int id) async {
|
||||||
|
final row = await (drift.storeEntity.select()..where((t) => t.id.equals(id))).getSingleOrNull();
|
||||||
|
return row?.intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _deleteLegacyStoreRows(Drift drift, List<int> ids) async {
|
||||||
|
if (ids.isEmpty) return;
|
||||||
|
await (drift.storeEntity.delete()..where((t) => t.id.isIn(ids))).go();
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
|
import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
|
||||||
@@ -30,7 +31,7 @@ class AdvancedSettings extends HookConsumerWidget {
|
|||||||
final manageLocalMediaAndroid = useAppSettingsState(AppSettingsEnum.manageLocalMediaAndroid);
|
final manageLocalMediaAndroid = useAppSettingsState(AppSettingsEnum.manageLocalMediaAndroid);
|
||||||
final isManageMediaSupported = useState(false);
|
final isManageMediaSupported = useState(false);
|
||||||
final manageMediaAndroidPermission = useState(false);
|
final manageMediaAndroidPermission = useState(false);
|
||||||
final levelId = useAppSettingsState(AppSettingsEnum.logLevel);
|
final levelId = useState<int>(ref.read(systemConfigProvider).log.level.index);
|
||||||
final preferRemote = useAppSettingsState(AppSettingsEnum.preferRemoteImage);
|
final preferRemote = useAppSettingsState(AppSettingsEnum.preferRemoteImage);
|
||||||
final readonlyModeEnabled = useAppSettingsState(AppSettingsEnum.readonlyModeEnabled);
|
final readonlyModeEnabled = useAppSettingsState(AppSettingsEnum.readonlyModeEnabled);
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,30 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/metadata.provider.dart';
|
||||||
import 'package:immich_mobile/providers/theme.provider.dart';
|
import 'package:immich_mobile/providers/theme.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||||
|
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/preference_settings/primary_color_setting.dart';
|
import 'package:immich_mobile/widgets/settings/preference_settings/primary_color_setting.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
|
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
|
||||||
|
|
||||||
class ThemeSetting extends HookConsumerWidget {
|
class ThemeSetting extends HookConsumerWidget {
|
||||||
const ThemeSetting({super.key});
|
const ThemeSetting({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final currentThemeString = useAppSettingsState(AppSettingsEnum.themeMode);
|
final currentTheme = useState(ref.read(immichThemeModeProvider));
|
||||||
final currentTheme = useValueNotifier(ref.read(immichThemeModeProvider));
|
|
||||||
final isDarkTheme = useValueNotifier(currentTheme.value == ThemeMode.dark);
|
final isDarkTheme = useValueNotifier(currentTheme.value == ThemeMode.dark);
|
||||||
final isSystemTheme = useValueNotifier(currentTheme.value == ThemeMode.system);
|
final isSystemTheme = useValueNotifier(currentTheme.value == ThemeMode.system);
|
||||||
|
|
||||||
final applyThemeToBackgroundSetting = useAppSettingsState(AppSettingsEnum.colorfulInterface);
|
final applyThemeToBackgroundSetting = useAppSettingsState(AppSettingsEnum.colorfulInterface);
|
||||||
final applyThemeToBackgroundProvider = useValueNotifier(ref.read(colorfulInterfaceSettingProvider));
|
final applyThemeToBackgroundProvider = useValueNotifier(ref.read(colorfulInterfaceSettingProvider));
|
||||||
|
|
||||||
useValueChanged(
|
|
||||||
currentThemeString.value,
|
|
||||||
(_, __) => currentTheme.value = switch (currentThemeString.value) {
|
|
||||||
"light" => ThemeMode.light,
|
|
||||||
"dark" => ThemeMode.dark,
|
|
||||||
_ => ThemeMode.system,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
useValueChanged(
|
useValueChanged(
|
||||||
applyThemeToBackgroundSetting.value,
|
applyThemeToBackgroundSetting.value,
|
||||||
(_, __) => applyThemeToBackgroundProvider.value = applyThemeToBackgroundSetting.value,
|
(_, __) => applyThemeToBackgroundProvider.value = applyThemeToBackgroundSetting.value,
|
||||||
@@ -40,16 +33,17 @@ class ThemeSetting extends HookConsumerWidget {
|
|||||||
void onThemeChange(bool isDark) {
|
void onThemeChange(bool isDark) {
|
||||||
if (isDark) {
|
if (isDark) {
|
||||||
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.dark;
|
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.dark;
|
||||||
currentThemeString.value = "dark";
|
currentTheme.value = ThemeMode.dark;
|
||||||
} else {
|
} else {
|
||||||
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.light;
|
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.light;
|
||||||
currentThemeString.value = "light";
|
currentTheme.value = ThemeMode.light;
|
||||||
}
|
}
|
||||||
|
ref.read(metadataProvider).setAppConfig((config) => config.copyWith(themeMode: currentTheme.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSystemThemeChange(bool isSystem) {
|
void onSystemThemeChange(bool isSystem) {
|
||||||
if (isSystem) {
|
if (isSystem) {
|
||||||
currentThemeString.value = "system";
|
currentTheme.value = ThemeMode.system;
|
||||||
isSystemTheme.value = true;
|
isSystemTheme.value = true;
|
||||||
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.system;
|
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.system;
|
||||||
} else {
|
} else {
|
||||||
@@ -57,13 +51,16 @@ class ThemeSetting extends HookConsumerWidget {
|
|||||||
isSystemTheme.value = false;
|
isSystemTheme.value = false;
|
||||||
isDarkTheme.value = currentSystemBrightness == Brightness.dark;
|
isDarkTheme.value = currentSystemBrightness == Brightness.dark;
|
||||||
if (currentSystemBrightness == Brightness.light) {
|
if (currentSystemBrightness == Brightness.light) {
|
||||||
currentThemeString.value = "light";
|
currentTheme.value = ThemeMode.light;
|
||||||
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.light;
|
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.light;
|
||||||
} else if (currentSystemBrightness == Brightness.dark) {
|
} else if (currentSystemBrightness == Brightness.dark) {
|
||||||
currentThemeString.value = "dark";
|
currentTheme.value = ThemeMode.dark;
|
||||||
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.dark;
|
ref.watch(immichThemeModeProvider.notifier).state = ThemeMode.dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ref
|
||||||
|
.read(metadataProvider)
|
||||||
|
.update(MetadataKind.appConfig, (appConfig) => appConfig.copyWith(themeMode: currentTheme.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSurfaceColorSettingChange(bool useColorfulInterface) {
|
void onSurfaceColorSettingChange(bool useColorfulInterface) {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/log_config.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/config/system_config.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/metadata_kind.dart';
|
||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
|
||||||
@@ -29,21 +30,26 @@ final _kWarnLog = LogMessage(
|
|||||||
void main() {
|
void main() {
|
||||||
late LogService sut;
|
late LogService sut;
|
||||||
late LogRepository mockLogRepo;
|
late LogRepository mockLogRepo;
|
||||||
late DriftStoreRepository mockStoreRepo;
|
late MockCachedMetadataRepository mockMetadataRepository;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
mockLogRepo = MockLogRepository();
|
mockLogRepo = MockLogRepository();
|
||||||
mockStoreRepo = MockDriftStoreRepository();
|
mockMetadataRepository = MockCachedMetadataRepository();
|
||||||
|
|
||||||
registerFallbackValue(_kInfoLog);
|
registerFallbackValue(_kInfoLog);
|
||||||
|
SystemConfig identityMutator(SystemConfig c) => c;
|
||||||
|
registerFallbackValue(identityMutator);
|
||||||
|
|
||||||
when(() => mockLogRepo.truncate(limit: any(named: 'limit'))).thenAnswer((_) async => {});
|
when(() => mockLogRepo.truncate(limit: any(named: 'limit'))).thenAnswer((_) async => {});
|
||||||
when(() => mockStoreRepo.tryGet<int>(StoreKey.logLevel)).thenAnswer((_) async => LogLevel.fine.index);
|
when(
|
||||||
|
() => mockMetadataRepository.read(MetadataKind.systemConfig),
|
||||||
|
).thenReturn(const SystemConfig(log: LogConfig(level: LogLevel.fine)));
|
||||||
|
when(() => mockMetadataRepository.update<SystemConfig>(MetadataKind.systemConfig, any())).thenAnswer((_) async {});
|
||||||
when(() => mockLogRepo.getAll()).thenAnswer((_) async => []);
|
when(() => mockLogRepo.getAll()).thenAnswer((_) async => []);
|
||||||
when(() => mockLogRepo.insert(any())).thenAnswer((_) async => true);
|
when(() => mockLogRepo.insert(any())).thenAnswer((_) async => true);
|
||||||
when(() => mockLogRepo.insertAll(any())).thenAnswer((_) async => true);
|
when(() => mockLogRepo.insertAll(any())).thenAnswer((_) async => true);
|
||||||
|
|
||||||
sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo);
|
sut = await LogService.create(logRepository: mockLogRepo, metadataRepository: mockMetadataRepository);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
@@ -56,21 +62,25 @@ void main() {
|
|||||||
expect(limit, kLogTruncateLimit);
|
expect(limit, kLogTruncateLimit);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Sets log level based on the store setting', () {
|
test('Sets log level based on the metadata repository', () {
|
||||||
verify(() => mockStoreRepo.tryGet<int>(StoreKey.logLevel)).called(1);
|
verify(() => mockMetadataRepository.read(MetadataKind.systemConfig)).called(1);
|
||||||
expect(Logger.root.level, Level.FINE);
|
expect(Logger.root.level, Level.FINE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group("Log Service Set Level:", () {
|
group("Log Service Set Level:", () {
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
when(() => mockStoreRepo.upsert<int>(StoreKey.logLevel, any())).thenAnswer((_) async => true);
|
|
||||||
await sut.setLogLevel(LogLevel.shout);
|
await sut.setLogLevel(LogLevel.shout);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Updates the log level in store', () {
|
test('Updates the log level via metadata repository', () {
|
||||||
final index = verify(() => mockStoreRepo.upsert<int>(StoreKey.logLevel, captureAny())).captured.firstOrNull;
|
final mutator =
|
||||||
expect(index, LogLevel.shout.index);
|
verify(
|
||||||
|
() => mockMetadataRepository.update<SystemConfig>(MetadataKind.systemConfig, captureAny()),
|
||||||
|
).captured.firstOrNull
|
||||||
|
as SystemConfig Function(SystemConfig)?;
|
||||||
|
final result = mutator?.call(const SystemConfig());
|
||||||
|
expect(result?.log.level, LogLevel.shout);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Sets log level on logger', () {
|
test('Sets log level on logger', () {
|
||||||
@@ -81,7 +91,11 @@ void main() {
|
|||||||
group("Log Service Buffer:", () {
|
group("Log Service Buffer:", () {
|
||||||
test('Buffers logs until timer elapses', () {
|
test('Buffers logs until timer elapses', () {
|
||||||
TestUtils.fakeAsync((time) async {
|
TestUtils.fakeAsync((time) async {
|
||||||
sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true);
|
sut = await LogService.create(
|
||||||
|
logRepository: mockLogRepo,
|
||||||
|
metadataRepository: mockMetadataRepository,
|
||||||
|
shouldBuffer: true,
|
||||||
|
);
|
||||||
|
|
||||||
final logger = Logger(_kInfoLog.logger!);
|
final logger = Logger(_kInfoLog.logger!);
|
||||||
logger.info(_kInfoLog.message);
|
logger.info(_kInfoLog.message);
|
||||||
@@ -95,7 +109,11 @@ void main() {
|
|||||||
|
|
||||||
test('Batch inserts all logs on timer', () {
|
test('Batch inserts all logs on timer', () {
|
||||||
TestUtils.fakeAsync((time) async {
|
TestUtils.fakeAsync((time) async {
|
||||||
sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true);
|
sut = await LogService.create(
|
||||||
|
logRepository: mockLogRepo,
|
||||||
|
metadataRepository: mockMetadataRepository,
|
||||||
|
shouldBuffer: true,
|
||||||
|
);
|
||||||
|
|
||||||
final logger = Logger(_kInfoLog.logger!);
|
final logger = Logger(_kInfoLog.logger!);
|
||||||
logger.info(_kInfoLog.message);
|
logger.info(_kInfoLog.message);
|
||||||
@@ -112,7 +130,11 @@ void main() {
|
|||||||
|
|
||||||
test('Does not buffer when off', () {
|
test('Does not buffer when off', () {
|
||||||
TestUtils.fakeAsync((time) async {
|
TestUtils.fakeAsync((time) async {
|
||||||
sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: false);
|
sut = await LogService.create(
|
||||||
|
logRepository: mockLogRepo,
|
||||||
|
metadataRepository: mockMetadataRepository,
|
||||||
|
shouldBuffer: false,
|
||||||
|
);
|
||||||
|
|
||||||
final logger = Logger(_kInfoLog.logger!);
|
final logger = Logger(_kInfoLog.logger!);
|
||||||
logger.info(_kInfoLog.message);
|
logger.info(_kInfoLog.message);
|
||||||
@@ -142,7 +164,11 @@ void main() {
|
|||||||
|
|
||||||
test('Combines result from both DB + Buffer', () {
|
test('Combines result from both DB + Buffer', () {
|
||||||
TestUtils.fakeAsync((time) async {
|
TestUtils.fakeAsync((time) async {
|
||||||
sut = await LogService.create(logRepository: mockLogRepo, storeRepository: mockStoreRepo, shouldBuffer: true);
|
sut = await LogService.create(
|
||||||
|
logRepository: mockLogRepo,
|
||||||
|
metadataRepository: mockMetadataRepository,
|
||||||
|
shouldBuffer: true,
|
||||||
|
);
|
||||||
|
|
||||||
final logger = Logger(_kWarnLog.logger!);
|
final logger = Logger(_kWarnLog.logger!);
|
||||||
logger.warning(_kWarnLog.message);
|
logger.warning(_kWarnLog.message);
|
||||||
|
|||||||
+4
@@ -28,6 +28,7 @@ import 'schema_v21.dart' as v21;
|
|||||||
import 'schema_v22.dart' as v22;
|
import 'schema_v22.dart' as v22;
|
||||||
import 'schema_v23.dart' as v23;
|
import 'schema_v23.dart' as v23;
|
||||||
import 'schema_v24.dart' as v24;
|
import 'schema_v24.dart' as v24;
|
||||||
|
import 'schema_v25.dart' as v25;
|
||||||
|
|
||||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||||
@override
|
@override
|
||||||
@@ -81,6 +82,8 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
return v23.DatabaseAtV23(db);
|
return v23.DatabaseAtV23(db);
|
||||||
case 24:
|
case 24:
|
||||||
return v24.DatabaseAtV24(db);
|
return v24.DatabaseAtV24(db);
|
||||||
|
case 25:
|
||||||
|
return v25.DatabaseAtV25(db);
|
||||||
default:
|
default:
|
||||||
throw MissingSchemaException(version, versions);
|
throw MissingSchemaException(version, versions);
|
||||||
}
|
}
|
||||||
@@ -111,5 +114,6 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
22,
|
22,
|
||||||
23,
|
23,
|
||||||
24,
|
24,
|
||||||
|
25,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
+9345
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/cached_metadata.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
||||||
@@ -17,6 +18,8 @@ import 'package:mocktail/mocktail.dart';
|
|||||||
|
|
||||||
class MockDriftStoreRepository extends Mock implements DriftStoreRepository {}
|
class MockDriftStoreRepository extends Mock implements DriftStoreRepository {}
|
||||||
|
|
||||||
|
class MockCachedMetadataRepository extends Mock implements CachedMetadataRepository {}
|
||||||
|
|
||||||
class MockLogRepository extends Mock implements LogRepository {}
|
class MockLogRepository extends Mock implements LogRepository {}
|
||||||
|
|
||||||
class MockSyncStreamRepository extends Mock implements SyncStreamRepository {}
|
class MockSyncStreamRepository extends Mock implements SyncStreamRepository {}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:mocktail/mocktail.dart';
|
|||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
import '../domain/service.mock.dart';
|
import '../domain/service.mock.dart';
|
||||||
|
import '../infrastructure/repository.mock.dart';
|
||||||
import '../repository.mocks.dart';
|
import '../repository.mocks.dart';
|
||||||
import '../service.mocks.dart';
|
import '../service.mocks.dart';
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ void main() {
|
|||||||
late MockNetworkService networkService;
|
late MockNetworkService networkService;
|
||||||
late MockBackgroundSyncManager backgroundSyncManager;
|
late MockBackgroundSyncManager backgroundSyncManager;
|
||||||
late MockAppSettingService appSettingsService;
|
late MockAppSettingService appSettingsService;
|
||||||
|
late MockCachedMetadataRepository metadataRepository;
|
||||||
late Drift db;
|
late Drift db;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
@@ -32,6 +34,7 @@ void main() {
|
|||||||
networkService = MockNetworkService();
|
networkService = MockNetworkService();
|
||||||
backgroundSyncManager = MockBackgroundSyncManager();
|
backgroundSyncManager = MockBackgroundSyncManager();
|
||||||
appSettingsService = MockAppSettingService();
|
appSettingsService = MockAppSettingService();
|
||||||
|
metadataRepository = MockCachedMetadataRepository();
|
||||||
|
|
||||||
sut = AuthService(
|
sut = AuthService(
|
||||||
authApiRepository,
|
authApiRepository,
|
||||||
@@ -40,6 +43,7 @@ void main() {
|
|||||||
networkService,
|
networkService,
|
||||||
backgroundSyncManager,
|
backgroundSyncManager,
|
||||||
appSettingsService,
|
appSettingsService,
|
||||||
|
metadataRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
registerFallbackValue(Uri());
|
registerFallbackValue(Uri());
|
||||||
|
|||||||
Reference in New Issue
Block a user