#170 perf: collection sort/group by name, save/load top entries
This commit is contained in:
parent
6c145d5bb5
commit
8b1180684c
67 changed files with 544 additions and 318 deletions
|
@ -141,7 +141,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
@ -152,10 +152,10 @@ dependencies {
|
|||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:876e53870a'
|
||||
// forked, built by JitPack, cf https://jitpack.io/p/deckerst/pixymeta-android
|
||||
implementation 'com.github.deckerst:pixymeta-android:706bd73d6e'
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
implementation 'com.github.bumptech.glide:glide:4.13.0'
|
||||
|
||||
kapt 'androidx.annotation:annotation:1.3.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.13.0'
|
||||
|
||||
compileOnly rootProject.findProject(':streams_channel')
|
||||
}
|
||||
|
|
|
@ -32,12 +32,12 @@ import deckers.thibault.aves.utils.UriUtils.tryParseId
|
|||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.util.PathUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.beyka.tiffbitmapfactory.TiffBitmapFactory
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class DebugHandler(private val context: Context) : MethodCallHandler {
|
||||
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||
|
@ -81,7 +81,16 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
put("dataDir", context.dataDir)
|
||||
}
|
||||
}.mapValues { it.value?.path }
|
||||
}.mapValues { it.value?.path }.toMutableMap()
|
||||
|
||||
// used by flutter plugin `path_provider`
|
||||
dirs.putAll(
|
||||
hashMapOf(
|
||||
"flutter / cacheDir" to PathUtils.getCacheDirectory(context),
|
||||
"flutter / dataDir" to PathUtils.getDataDirectory(context),
|
||||
"flutter / filesDir" to PathUtils.getFilesDir(context),
|
||||
)
|
||||
)
|
||||
|
||||
result.success(dirs)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.0'
|
||||
classpath 'com.android.tools.build:gradle:7.1.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// GMS & Firebase Crashlytics are not actually used by all flavors
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
|
|
95
lib/model/db/db_metadata.dart
Normal file
95
lib/model/db/db_metadata.dart
Normal file
|
@ -0,0 +1,95 @@
|
|||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/metadata/address.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/video_playback.dart';
|
||||
|
||||
abstract class MetadataDb {
|
||||
Future<void> init();
|
||||
|
||||
Future<int> dbFileSize();
|
||||
|
||||
Future<void> reset();
|
||||
|
||||
Future<void> removeIds(Set<int> contentIds, {Set<EntryDataType>? dataTypes});
|
||||
|
||||
// entries
|
||||
|
||||
Future<void> clearEntries();
|
||||
|
||||
Future<Set<AvesEntry>> loadAllEntries();
|
||||
|
||||
Future<void> saveEntries(Iterable<AvesEntry> entries);
|
||||
|
||||
Future<void> updateEntryId(int oldId, AvesEntry entry);
|
||||
|
||||
Future<Set<AvesEntry>> searchEntries(String query, {int? limit});
|
||||
|
||||
Future<Set<AvesEntry>> loadEntries(List<int> ids);
|
||||
|
||||
// date taken
|
||||
|
||||
Future<void> clearDates();
|
||||
|
||||
Future<Map<int?, int?>> loadDates();
|
||||
|
||||
// catalog metadata
|
||||
|
||||
Future<void> clearMetadataEntries();
|
||||
|
||||
Future<List<CatalogMetadata>> loadAllMetadataEntries();
|
||||
|
||||
Future<void> saveMetadata(Set<CatalogMetadata> metadataEntries);
|
||||
|
||||
Future<void> updateMetadataId(int oldId, CatalogMetadata? metadata);
|
||||
|
||||
// address
|
||||
|
||||
Future<void> clearAddresses();
|
||||
|
||||
Future<List<AddressDetails>> loadAllAddresses();
|
||||
|
||||
Future<void> saveAddresses(Set<AddressDetails> addresses);
|
||||
|
||||
Future<void> updateAddressId(int oldId, AddressDetails? address);
|
||||
|
||||
// favourites
|
||||
|
||||
Future<void> clearFavourites();
|
||||
|
||||
Future<Set<FavouriteRow>> loadAllFavourites();
|
||||
|
||||
Future<void> addFavourites(Iterable<FavouriteRow> rows);
|
||||
|
||||
Future<void> updateFavouriteId(int oldId, FavouriteRow row);
|
||||
|
||||
Future<void> removeFavourites(Iterable<FavouriteRow> rows);
|
||||
|
||||
// covers
|
||||
|
||||
Future<void> clearCovers();
|
||||
|
||||
Future<Set<CoverRow>> loadAllCovers();
|
||||
|
||||
Future<void> addCovers(Iterable<CoverRow> rows);
|
||||
|
||||
Future<void> updateCoverEntryId(int oldId, CoverRow row);
|
||||
|
||||
Future<void> removeCovers(Set<CollectionFilter> filters);
|
||||
|
||||
// video playback
|
||||
|
||||
Future<void> clearVideoPlayback();
|
||||
|
||||
Future<Set<VideoPlaybackRow>> loadAllVideoPlayback();
|
||||
|
||||
Future<VideoPlaybackRow?> loadVideoPlayback(int? contentId);
|
||||
|
||||
Future<void> addVideoPlayback(Set<VideoPlaybackRow> rows);
|
||||
|
||||
Future<void> updateVideoPlaybackId(int oldId, int? newId);
|
||||
|
||||
Future<void> removeVideoPlayback(Set<int> contentIds);
|
||||
}
|
|
@ -1,104 +1,19 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db_metadata_sqflite_upgrade.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/favourites.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/metadata/address.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata_db_upgrade.dart';
|
||||
import 'package:aves/model/video_playback.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
abstract class MetadataDb {
|
||||
Future<void> init();
|
||||
|
||||
Future<int> dbFileSize();
|
||||
|
||||
Future<void> reset();
|
||||
|
||||
Future<void> removeIds(Set<int> contentIds, {Set<EntryDataType>? dataTypes});
|
||||
|
||||
// entries
|
||||
|
||||
Future<void> clearEntries();
|
||||
|
||||
Future<Set<AvesEntry>> loadAllEntries();
|
||||
|
||||
Future<void> saveEntries(Iterable<AvesEntry> entries);
|
||||
|
||||
Future<void> updateEntryId(int oldId, AvesEntry entry);
|
||||
|
||||
Future<Set<AvesEntry>> searchEntries(String query, {int? limit});
|
||||
|
||||
// date taken
|
||||
|
||||
Future<void> clearDates();
|
||||
|
||||
Future<Map<int?, int?>> loadDates();
|
||||
|
||||
// catalog metadata
|
||||
|
||||
Future<void> clearMetadataEntries();
|
||||
|
||||
Future<List<CatalogMetadata>> loadAllMetadataEntries();
|
||||
|
||||
Future<void> saveMetadata(Set<CatalogMetadata> metadataEntries);
|
||||
|
||||
Future<void> updateMetadataId(int oldId, CatalogMetadata? metadata);
|
||||
|
||||
// address
|
||||
|
||||
Future<void> clearAddresses();
|
||||
|
||||
Future<List<AddressDetails>> loadAllAddresses();
|
||||
|
||||
Future<void> saveAddresses(Set<AddressDetails> addresses);
|
||||
|
||||
Future<void> updateAddressId(int oldId, AddressDetails? address);
|
||||
|
||||
// favourites
|
||||
|
||||
Future<void> clearFavourites();
|
||||
|
||||
Future<Set<FavouriteRow>> loadAllFavourites();
|
||||
|
||||
Future<void> addFavourites(Iterable<FavouriteRow> rows);
|
||||
|
||||
Future<void> updateFavouriteId(int oldId, FavouriteRow row);
|
||||
|
||||
Future<void> removeFavourites(Iterable<FavouriteRow> rows);
|
||||
|
||||
// covers
|
||||
|
||||
Future<void> clearCovers();
|
||||
|
||||
Future<Set<CoverRow>> loadAllCovers();
|
||||
|
||||
Future<void> addCovers(Iterable<CoverRow> rows);
|
||||
|
||||
Future<void> updateCoverEntryId(int oldId, CoverRow row);
|
||||
|
||||
Future<void> removeCovers(Set<CollectionFilter> filters);
|
||||
|
||||
// video playback
|
||||
|
||||
Future<void> clearVideoPlayback();
|
||||
|
||||
Future<Set<VideoPlaybackRow>> loadAllVideoPlayback();
|
||||
|
||||
Future<VideoPlaybackRow?> loadVideoPlayback(int? contentId);
|
||||
|
||||
Future<void> addVideoPlayback(Set<VideoPlaybackRow> rows);
|
||||
|
||||
Future<void> updateVideoPlaybackId(int oldId, int? newId);
|
||||
|
||||
Future<void> removeVideoPlayback(Set<int> contentIds);
|
||||
}
|
||||
|
||||
class SqfliteMetadataDb implements MetadataDb {
|
||||
late Future<Database> _database;
|
||||
|
||||
|
@ -235,6 +150,24 @@ class SqfliteMetadataDb implements MetadataDb {
|
|||
return entries;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Set<AvesEntry>> loadEntries(List<int> ids) async {
|
||||
if (ids.isEmpty) return {};
|
||||
final db = await _database;
|
||||
final entries = <AvesEntry>{};
|
||||
await Future.forEach(ids, (id) async {
|
||||
final maps = await db.query(
|
||||
entryTable,
|
||||
where: 'contentId = ?',
|
||||
whereArgs: [id],
|
||||
);
|
||||
if (maps.isNotEmpty) {
|
||||
entries.add(AvesEntry.fromMap(maps.first));
|
||||
}
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveEntries(Iterable<AvesEntry> entries) async {
|
||||
if (entries.isEmpty) return;
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:aves/model/db/db_metadata_sqflite.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:aves/l10n/l10n.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/geo_utils.dart';
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:aves/model/actions/entry_set_actions.dart';
|
|||
import 'package:aves/model/actions/video_actions.dart';
|
||||
import 'package:aves/model/filters/favourite.dart';
|
||||
import 'package:aves/model/filters/mime.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/source/enums.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
|
@ -106,4 +106,8 @@ class SettingsDefaults {
|
|||
|
||||
// file picker
|
||||
static const filePickerShowHiddenFiles = false;
|
||||
|
||||
// platform settings
|
||||
static const isRotationLocked = false;
|
||||
static const areAnimationsRemoved = false;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,14 @@ import 'package:aves/model/actions/entry_set_actions.dart';
|
|||
import 'package:aves/model/actions/video_actions.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/defaults.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/source/enums.dart';
|
||||
import 'package:aves/services/accessibility_service.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
final Settings settings = Settings._private();
|
||||
|
||||
|
@ -25,8 +24,6 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
Stream<String> get updateStream => _updateStreamController.stream;
|
||||
|
||||
static SharedPreferences? _prefs;
|
||||
|
||||
Settings._private();
|
||||
|
||||
static const Set<String> internalKeys = {
|
||||
|
@ -34,6 +31,9 @@ class Settings extends ChangeNotifier {
|
|||
catalogTimeZoneKey,
|
||||
videoShowRawTimedTextKey,
|
||||
searchHistoryKey,
|
||||
platformAccelerometerRotationKey,
|
||||
platformTransitionAnimationScaleKey,
|
||||
topEntryIdsKey,
|
||||
};
|
||||
|
||||
// app
|
||||
|
@ -48,6 +48,7 @@ class Settings extends ChangeNotifier {
|
|||
static const catalogTimeZoneKey = 'catalog_time_zone';
|
||||
static const tileExtentPrefixKey = 'tile_extent_';
|
||||
static const tileLayoutPrefixKey = 'tile_layout_';
|
||||
static const topEntryIdsKey = 'top_entry_ids';
|
||||
|
||||
// drawer
|
||||
static const drawerTypeBookmarksKey = 'drawer_type_bookmarks';
|
||||
|
@ -124,16 +125,10 @@ class Settings extends ChangeNotifier {
|
|||
// cf Android `Settings.Global.TRANSITION_ANIMATION_SCALE`
|
||||
static const platformTransitionAnimationScaleKey = 'transition_animation_scale';
|
||||
|
||||
bool get initialized => _prefs != null;
|
||||
bool get initialized => settingsStore.initialized;
|
||||
|
||||
Future<void> init({
|
||||
required bool monitorPlatformSettings,
|
||||
bool isRotationLocked = false,
|
||||
bool areAnimationsRemoved = false,
|
||||
}) async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
_isRotationLocked = isRotationLocked;
|
||||
_areAnimationsRemoved = areAnimationsRemoved;
|
||||
Future<void> init({required bool monitorPlatformSettings}) async {
|
||||
await settingsStore.init();
|
||||
if (monitorPlatformSettings) {
|
||||
_platformSettingsChangeChannel.receiveBroadcastStream().listen((event) => _onPlatformSettingsChange(event as Map?));
|
||||
}
|
||||
|
@ -141,9 +136,9 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
Future<void> reset({required bool includeInternalKeys}) async {
|
||||
if (includeInternalKeys) {
|
||||
await _prefs!.clear();
|
||||
await settingsStore.clear();
|
||||
} else {
|
||||
await Future.forEach<String>(_prefs!.getKeys().whereNot(internalKeys.contains), _prefs!.remove);
|
||||
await Future.forEach<String>(settingsStore.getKeys().whereNot(Settings.internalKeys.contains), settingsStore.remove);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +184,7 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
Locale? get locale {
|
||||
// exceptionally allow getting locale before settings are initialized
|
||||
final tag = _prefs?.getString(localeKey);
|
||||
final tag = initialized ? getString(localeKey) : null;
|
||||
if (tag != null) {
|
||||
final codes = tag.split(localeSeparator);
|
||||
return Locale.fromSubtags(
|
||||
|
@ -250,11 +245,11 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set homePage(HomePageSetting newValue) => setAndNotify(homePageKey, newValue.toString());
|
||||
|
||||
String get catalogTimeZone => _prefs!.getString(catalogTimeZoneKey) ?? '';
|
||||
String get catalogTimeZone => getString(catalogTimeZoneKey) ?? '';
|
||||
|
||||
set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue);
|
||||
|
||||
double getTileExtent(String routeName) => _prefs!.getDouble(tileExtentPrefixKey + routeName) ?? 0;
|
||||
double getTileExtent(String routeName) => getDouble(tileExtentPrefixKey + routeName) ?? 0;
|
||||
|
||||
void setTileExtent(String routeName, double newValue) => setAndNotify(tileExtentPrefixKey + routeName, newValue);
|
||||
|
||||
|
@ -262,10 +257,14 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
void setTileLayout(String routeName, TileLayout newValue) => setAndNotify(tileLayoutPrefixKey + routeName, newValue.toString());
|
||||
|
||||
List<int>? get topEntryIds => getStringList(topEntryIdsKey)?.map(int.tryParse).whereNotNull().toList();
|
||||
|
||||
set topEntryIds(List<int>? newValue) => setAndNotify(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList());
|
||||
|
||||
// drawer
|
||||
|
||||
List<CollectionFilter?> get drawerTypeBookmarks =>
|
||||
(_prefs!.getStringList(drawerTypeBookmarksKey))?.map((v) {
|
||||
(getStringList(drawerTypeBookmarksKey))?.map((v) {
|
||||
if (v.isEmpty) return null;
|
||||
return CollectionFilter.fromJson(v);
|
||||
}).toList() ??
|
||||
|
@ -273,11 +272,11 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set drawerTypeBookmarks(List<CollectionFilter?> newValue) => setAndNotify(drawerTypeBookmarksKey, newValue.map((filter) => filter?.toJson() ?? '').toList());
|
||||
|
||||
List<String>? get drawerAlbumBookmarks => _prefs!.getStringList(drawerAlbumBookmarksKey);
|
||||
List<String>? get drawerAlbumBookmarks => getStringList(drawerAlbumBookmarksKey);
|
||||
|
||||
set drawerAlbumBookmarks(List<String>? newValue) => setAndNotify(drawerAlbumBookmarksKey, newValue);
|
||||
|
||||
List<String> get drawerPageBookmarks => _prefs!.getStringList(drawerPageBookmarksKey) ?? SettingsDefaults.drawerPageBookmarks;
|
||||
List<String> get drawerPageBookmarks => getStringList(drawerPageBookmarksKey) ?? SettingsDefaults.drawerPageBookmarks;
|
||||
|
||||
set drawerPageBookmarks(List<String> newValue) => setAndNotify(drawerPageBookmarksKey, newValue);
|
||||
|
||||
|
@ -341,11 +340,11 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set tagSortFactor(ChipSortFactor newValue) => setAndNotify(tagSortFactorKey, newValue.toString());
|
||||
|
||||
Set<CollectionFilter> get pinnedFilters => (_prefs!.getStringList(pinnedFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||
Set<CollectionFilter> get pinnedFilters => (getStringList(pinnedFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||
|
||||
set pinnedFilters(Set<CollectionFilter> newValue) => setAndNotify(pinnedFiltersKey, newValue.map((filter) => filter.toJson()).toList());
|
||||
|
||||
Set<CollectionFilter> get hiddenFilters => (_prefs!.getStringList(hiddenFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||
Set<CollectionFilter> get hiddenFilters => (getStringList(hiddenFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
|
||||
|
||||
set hiddenFilters(Set<CollectionFilter> newValue) => setAndNotify(hiddenFiltersKey, newValue.map((filter) => filter.toJson()).toList());
|
||||
|
||||
|
@ -415,7 +414,7 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
// subtitles
|
||||
|
||||
double get subtitleFontSize => _prefs!.getDouble(subtitleFontSizeKey) ?? SettingsDefaults.subtitleFontSize;
|
||||
double get subtitleFontSize => getDouble(subtitleFontSizeKey) ?? SettingsDefaults.subtitleFontSize;
|
||||
|
||||
set subtitleFontSize(double newValue) => setAndNotify(subtitleFontSizeKey, newValue);
|
||||
|
||||
|
@ -427,11 +426,11 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set subtitleShowOutline(bool newValue) => setAndNotify(subtitleShowOutlineKey, newValue);
|
||||
|
||||
Color get subtitleTextColor => Color(_prefs!.getInt(subtitleTextColorKey) ?? SettingsDefaults.subtitleTextColor.value);
|
||||
Color get subtitleTextColor => Color(getInt(subtitleTextColorKey) ?? SettingsDefaults.subtitleTextColor.value);
|
||||
|
||||
set subtitleTextColor(Color newValue) => setAndNotify(subtitleTextColorKey, newValue.value);
|
||||
|
||||
Color get subtitleBackgroundColor => Color(_prefs!.getInt(subtitleBackgroundColorKey) ?? SettingsDefaults.subtitleBackgroundColor.value);
|
||||
Color get subtitleBackgroundColor => Color(getInt(subtitleBackgroundColorKey) ?? SettingsDefaults.subtitleBackgroundColor.value);
|
||||
|
||||
set subtitleBackgroundColor(Color newValue) => setAndNotify(subtitleBackgroundColorKey, newValue.value);
|
||||
|
||||
|
@ -441,7 +440,7 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString());
|
||||
|
||||
double get infoMapZoom => _prefs!.getDouble(infoMapZoomKey) ?? SettingsDefaults.infoMapZoom;
|
||||
double get infoMapZoom => getDouble(infoMapZoomKey) ?? SettingsDefaults.infoMapZoom;
|
||||
|
||||
set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue);
|
||||
|
||||
|
@ -459,7 +458,7 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set saveSearchHistory(bool newValue) => setAndNotify(saveSearchHistoryKey, newValue);
|
||||
|
||||
List<CollectionFilter> get searchHistory => (_prefs!.getStringList(searchHistoryKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toList();
|
||||
List<CollectionFilter> get searchHistory => (getStringList(searchHistoryKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toList();
|
||||
|
||||
set searchHistory(List<CollectionFilter> newValue) => setAndNotify(searchHistoryKey, newValue.map((filter) => filter.toJson()).toList());
|
||||
|
||||
|
@ -481,11 +480,19 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
// convenience methods
|
||||
|
||||
int? getInt(String key) => settingsStore.getInt(key);
|
||||
|
||||
double? getDouble(String key) => settingsStore.getDouble(key);
|
||||
|
||||
String? getString(String key) => settingsStore.getString(key);
|
||||
|
||||
List<String>? getStringList(String key) => settingsStore.getStringList(key);
|
||||
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
bool getBoolOrDefault(String key, bool defaultValue) => _prefs!.getBool(key) ?? defaultValue;
|
||||
bool getBoolOrDefault(String key, bool defaultValue) => settingsStore.getBool(key) ?? defaultValue;
|
||||
|
||||
T getEnumOrDefault<T>(String key, T defaultValue, Iterable<T> values) {
|
||||
final valueString = _prefs!.getString(key);
|
||||
final valueString = settingsStore.getString(key);
|
||||
for (final v in values) {
|
||||
if (v.toString() == valueString) {
|
||||
return v;
|
||||
|
@ -495,28 +502,28 @@ class Settings extends ChangeNotifier {
|
|||
}
|
||||
|
||||
List<T> getEnumListOrDefault<T extends Object>(String key, List<T> defaultValue, Iterable<T> values) {
|
||||
return _prefs!.getStringList(key)?.map((s) => values.firstWhereOrNull((v) => v.toString() == s)).whereNotNull().toList() ?? defaultValue;
|
||||
return settingsStore.getStringList(key)?.map((s) => values.firstWhereOrNull((v) => v.toString() == s)).whereNotNull().toList() ?? defaultValue;
|
||||
}
|
||||
|
||||
void setAndNotify(String key, dynamic newValue) {
|
||||
var oldValue = _prefs!.get(key);
|
||||
var oldValue = settingsStore.get(key);
|
||||
if (newValue == null) {
|
||||
_prefs!.remove(key);
|
||||
settingsStore.remove(key);
|
||||
} else if (newValue is String) {
|
||||
oldValue = _prefs!.getString(key);
|
||||
_prefs!.setString(key, newValue);
|
||||
oldValue = settingsStore.getString(key);
|
||||
settingsStore.setString(key, newValue);
|
||||
} else if (newValue is List<String>) {
|
||||
oldValue = _prefs!.getStringList(key);
|
||||
_prefs!.setStringList(key, newValue);
|
||||
oldValue = settingsStore.getStringList(key);
|
||||
settingsStore.setStringList(key, newValue);
|
||||
} else if (newValue is int) {
|
||||
oldValue = _prefs!.getInt(key);
|
||||
_prefs!.setInt(key, newValue);
|
||||
oldValue = settingsStore.getInt(key);
|
||||
settingsStore.setInt(key, newValue);
|
||||
} else if (newValue is double) {
|
||||
oldValue = _prefs!.getDouble(key);
|
||||
_prefs!.setDouble(key, newValue);
|
||||
oldValue = settingsStore.getDouble(key);
|
||||
settingsStore.setDouble(key, newValue);
|
||||
} else if (newValue is bool) {
|
||||
oldValue = _prefs!.getBool(key);
|
||||
_prefs!.setBool(key, newValue);
|
||||
oldValue = settingsStore.getBool(key);
|
||||
settingsStore.setBool(key, newValue);
|
||||
}
|
||||
if (oldValue != newValue) {
|
||||
_updateStreamController.add(key);
|
||||
|
@ -527,50 +534,33 @@ class Settings extends ChangeNotifier {
|
|||
// platform settings
|
||||
|
||||
void _onPlatformSettingsChange(Map? fields) {
|
||||
var changed = false;
|
||||
fields?.forEach((key, value) {
|
||||
switch (key) {
|
||||
case platformAccelerometerRotationKey:
|
||||
if (value is num) {
|
||||
final newValue = value == 0;
|
||||
if (_isRotationLocked != newValue) {
|
||||
_isRotationLocked = newValue;
|
||||
if (!_isRotationLocked) {
|
||||
windowService.requestOrientation();
|
||||
}
|
||||
_updateStreamController.add(key);
|
||||
changed = true;
|
||||
}
|
||||
isRotationLocked = value == 0;
|
||||
}
|
||||
break;
|
||||
case platformTransitionAnimationScaleKey:
|
||||
if (value is num) {
|
||||
final newValue = value == 0;
|
||||
if (_areAnimationsRemoved != newValue) {
|
||||
_areAnimationsRemoved = newValue;
|
||||
_updateStreamController.add(key);
|
||||
changed = true;
|
||||
}
|
||||
areAnimationsRemoved = value == 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
bool _isRotationLocked = false;
|
||||
bool get isRotationLocked => getBoolOrDefault(platformAccelerometerRotationKey, SettingsDefaults.isRotationLocked);
|
||||
|
||||
bool get isRotationLocked => _isRotationLocked;
|
||||
set isRotationLocked(bool newValue) => setAndNotify(platformAccelerometerRotationKey, newValue);
|
||||
|
||||
bool _areAnimationsRemoved = false;
|
||||
bool get areAnimationsRemoved => getBoolOrDefault(platformTransitionAnimationScaleKey, SettingsDefaults.areAnimationsRemoved);
|
||||
|
||||
bool get areAnimationsRemoved => _areAnimationsRemoved;
|
||||
set areAnimationsRemoved(bool newValue) => setAndNotify(platformTransitionAnimationScaleKey, newValue);
|
||||
|
||||
// import/export
|
||||
|
||||
Map<String, dynamic> export() => Map.fromEntries(
|
||||
_prefs!.getKeys().whereNot(internalKeys.contains).map((k) => MapEntry(k, _prefs!.get(k))),
|
||||
settingsStore.getKeys().whereNot(internalKeys.contains).map((k) => MapEntry(k, settingsStore.get(k))),
|
||||
);
|
||||
|
||||
Future<void> import(dynamic jsonMap) async {
|
||||
|
@ -581,16 +571,16 @@ class Settings extends ChangeNotifier {
|
|||
// apply user modifications
|
||||
jsonMap.forEach((key, value) {
|
||||
if (value == null) {
|
||||
_prefs!.remove(key);
|
||||
settingsStore.remove(key);
|
||||
} else if (key.startsWith(tileExtentPrefixKey)) {
|
||||
if (value is double) {
|
||||
_prefs!.setDouble(key, value);
|
||||
settingsStore.setDouble(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a double');
|
||||
}
|
||||
} else if (key.startsWith(tileLayoutPrefixKey)) {
|
||||
if (value is String) {
|
||||
_prefs!.setString(key, value);
|
||||
settingsStore.setString(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a string');
|
||||
}
|
||||
|
@ -599,7 +589,7 @@ class Settings extends ChangeNotifier {
|
|||
case subtitleTextColorKey:
|
||||
case subtitleBackgroundColorKey:
|
||||
if (value is int) {
|
||||
_prefs!.setInt(key, value);
|
||||
settingsStore.setInt(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not an int');
|
||||
}
|
||||
|
@ -607,7 +597,7 @@ class Settings extends ChangeNotifier {
|
|||
case subtitleFontSizeKey:
|
||||
case infoMapZoomKey:
|
||||
if (value is double) {
|
||||
_prefs!.setDouble(key, value);
|
||||
settingsStore.setDouble(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a double');
|
||||
}
|
||||
|
@ -635,7 +625,7 @@ class Settings extends ChangeNotifier {
|
|||
case saveSearchHistoryKey:
|
||||
case filePickerShowHiddenFilesKey:
|
||||
if (value is bool) {
|
||||
_prefs!.setBool(key, value);
|
||||
settingsStore.setBool(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a bool');
|
||||
}
|
||||
|
@ -658,7 +648,7 @@ class Settings extends ChangeNotifier {
|
|||
case accessibilityAnimationsKey:
|
||||
case timeToTakeActionKey:
|
||||
if (value is String) {
|
||||
_prefs!.setString(key, value);
|
||||
settingsStore.setString(key, value);
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a string');
|
||||
}
|
||||
|
@ -673,7 +663,7 @@ class Settings extends ChangeNotifier {
|
|||
case viewerQuickActionsKey:
|
||||
case videoQuickActionsKey:
|
||||
if (value is List) {
|
||||
_prefs!.setStringList(key, value.cast<String>());
|
||||
settingsStore.setStringList(key, value.cast<String>());
|
||||
} else {
|
||||
debugPrint('failed to import key=$key, value=$value is not a list');
|
||||
}
|
||||
|
|
37
lib/model/settings/store/store.dart
Normal file
37
lib/model/settings/store/store.dart
Normal file
|
@ -0,0 +1,37 @@
|
|||
abstract class SettingsStore {
|
||||
bool get initialized;
|
||||
|
||||
Future<void> init();
|
||||
|
||||
Future<bool> clear();
|
||||
|
||||
Future<bool> remove(String key);
|
||||
|
||||
// get
|
||||
|
||||
Set<String> getKeys();
|
||||
|
||||
Object? get(String key);
|
||||
|
||||
bool? getBool(String key);
|
||||
|
||||
int? getInt(String key);
|
||||
|
||||
double? getDouble(String key);
|
||||
|
||||
String? getString(String key);
|
||||
|
||||
List<String>? getStringList(String key);
|
||||
|
||||
// set
|
||||
|
||||
Future<bool> setBool(String key, bool value);
|
||||
|
||||
Future<bool> setInt(String key, int value);
|
||||
|
||||
Future<bool> setDouble(String key, double value);
|
||||
|
||||
Future<bool> setString(String key, String value);
|
||||
|
||||
Future<bool> setStringList(String key, List<String> value);
|
||||
}
|
60
lib/model/settings/store/store_shared_pref.dart
Normal file
60
lib/model/settings/store/store_shared_pref.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:aves/model/settings/store/store.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SharedPrefSettingsStore implements SettingsStore {
|
||||
static SharedPreferences? _prefs;
|
||||
|
||||
@override
|
||||
bool get initialized => _prefs != null;
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> clear() => _prefs!.clear();
|
||||
|
||||
@override
|
||||
Future<bool> remove(String key) => _prefs!.remove(key);
|
||||
|
||||
// get
|
||||
|
||||
@override
|
||||
Set<String> getKeys() => _prefs!.getKeys();
|
||||
|
||||
@override
|
||||
Object? get(String key) => _prefs!.get(key);
|
||||
|
||||
@override
|
||||
bool? getBool(String key) => _prefs!.getBool(key);
|
||||
|
||||
@override
|
||||
int? getInt(String key) => _prefs!.getInt(key);
|
||||
|
||||
@override
|
||||
double? getDouble(String key) => _prefs!.getDouble(key);
|
||||
|
||||
@override
|
||||
String? getString(String key) => _prefs!.getString(key);
|
||||
|
||||
@override
|
||||
List<String>? getStringList(String key) => _prefs!.getStringList(key);
|
||||
|
||||
// set
|
||||
|
||||
@override
|
||||
Future<bool> setBool(String key, bool value) => _prefs!.setBool(key, value);
|
||||
|
||||
@override
|
||||
Future<bool> setInt(String key, int value) => _prefs!.setInt(key, value);
|
||||
|
||||
@override
|
||||
Future<bool> setDouble(String key, double value) => _prefs!.setDouble(key, value);
|
||||
|
||||
@override
|
||||
Future<bool> setString(String key, String value) => _prefs!.setString(key, value);
|
||||
|
||||
@override
|
||||
Future<bool> setStringList(String key, List<String> value) => _prefs!.setStringList(key, value);
|
||||
}
|
|
@ -26,56 +26,9 @@ mixin AlbumMixin on SourceBase {
|
|||
return compareAsciiUpperCase(va, vb);
|
||||
}
|
||||
|
||||
void _notifyAlbumChange() => eventBus.fire(AlbumsChangedEvent());
|
||||
|
||||
String getAlbumDisplayName(BuildContext? context, String dirPath) {
|
||||
final separator = pContext.separator;
|
||||
assert(!dirPath.endsWith(separator));
|
||||
|
||||
if (context != null) {
|
||||
final type = androidFileUtils.getAlbumType(dirPath);
|
||||
if (type == AlbumType.camera) return context.l10n.albumCamera;
|
||||
if (type == AlbumType.download) return context.l10n.albumDownload;
|
||||
if (type == AlbumType.screenshots) return context.l10n.albumScreenshots;
|
||||
if (type == AlbumType.screenRecordings) return context.l10n.albumScreenRecordings;
|
||||
if (type == AlbumType.videoCaptures) return context.l10n.albumVideoCaptures;
|
||||
}
|
||||
|
||||
final dir = VolumeRelativeDirectory.fromPath(dirPath);
|
||||
if (dir == null) return dirPath;
|
||||
|
||||
final relativeDir = dir.relativeDir;
|
||||
if (relativeDir.isEmpty) {
|
||||
final volume = androidFileUtils.getStorageVolume(dirPath)!;
|
||||
return volume.getDescription(context);
|
||||
}
|
||||
|
||||
String unique(String dirPath, Set<String?> others) {
|
||||
final parts = pContext.split(dirPath);
|
||||
for (var i = parts.length - 1; i > 0; i--) {
|
||||
final name = pContext.joinAll(['', ...parts.skip(i)]);
|
||||
final testName = '$separator$name';
|
||||
if (others.every((item) => !item!.endsWith(testName))) return name;
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
final otherAlbumsOnDevice = _directories.where((item) => item != dirPath).toSet();
|
||||
final uniqueNameInDevice = unique(dirPath, otherAlbumsOnDevice);
|
||||
if (uniqueNameInDevice.length <= relativeDir.length) {
|
||||
return uniqueNameInDevice;
|
||||
}
|
||||
|
||||
final volumePath = dir.volumePath;
|
||||
String trimVolumePath(String? path) => path!.substring(dir.volumePath.length);
|
||||
final otherAlbumsOnVolume = otherAlbumsOnDevice.where((path) => path!.startsWith(volumePath)).map(trimVolumePath).toSet();
|
||||
final uniqueNameInVolume = unique(trimVolumePath(dirPath), otherAlbumsOnVolume);
|
||||
final volume = androidFileUtils.getStorageVolume(dirPath)!;
|
||||
if (volume.isPrimary) {
|
||||
return uniqueNameInVolume;
|
||||
} else {
|
||||
return '$uniqueNameInVolume (${volume.getDescription(context)})';
|
||||
}
|
||||
void _onAlbumChanged() {
|
||||
invalidateAlbumDisplayNames();
|
||||
eventBus.fire(AlbumsChangedEvent());
|
||||
}
|
||||
|
||||
Map<String, AvesEntry?> getAlbumEntries() {
|
||||
|
@ -109,7 +62,7 @@ mixin AlbumMixin on SourceBase {
|
|||
void addDirectories(Set<String?> albums) {
|
||||
if (!_directories.containsAll(albums)) {
|
||||
_directories.addAll(albums);
|
||||
_notifyAlbumChange();
|
||||
_onAlbumChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,7 +70,7 @@ mixin AlbumMixin on SourceBase {
|
|||
final emptyAlbums = (albums ?? _directories).where((v) => _isEmptyAlbum(v) && !_newAlbums.contains(v)).toSet();
|
||||
if (emptyAlbums.isNotEmpty) {
|
||||
_directories.removeAll(emptyAlbums);
|
||||
_notifyAlbumChange();
|
||||
_onAlbumChanged();
|
||||
invalidateAlbumFilterSummary(directories: emptyAlbums);
|
||||
|
||||
final bookmarks = settings.drawerAlbumBookmarks;
|
||||
|
@ -165,6 +118,8 @@ mixin AlbumMixin on SourceBase {
|
|||
AvesEntry? albumRecentEntry(AlbumFilter filter) {
|
||||
return _filterRecentEntryMap.putIfAbsent(filter.album, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
|
||||
}
|
||||
|
||||
// new albums
|
||||
|
||||
void createAlbum(String directory) {
|
||||
_newAlbums.add(directory);
|
||||
|
@ -181,6 +136,80 @@ mixin AlbumMixin on SourceBase {
|
|||
void forgetNewAlbums(Set<String> directories) {
|
||||
_newAlbums.removeAll(directories);
|
||||
}
|
||||
|
||||
// display names
|
||||
|
||||
final Map<String, String> _albumDisplayNamesWithContext = {}, _albumDisplayNamesWithoutContext = {};
|
||||
|
||||
void invalidateAlbumDisplayNames() {
|
||||
_albumDisplayNamesWithContext.clear();
|
||||
_albumDisplayNamesWithoutContext.clear();
|
||||
}
|
||||
|
||||
String _computeDisplayName(BuildContext? context, String dirPath) {
|
||||
final separator = pContext.separator;
|
||||
assert(!dirPath.endsWith(separator));
|
||||
|
||||
if (context != null) {
|
||||
final type = androidFileUtils.getAlbumType(dirPath);
|
||||
switch (type) {
|
||||
case AlbumType.camera:
|
||||
return context.l10n.albumCamera;
|
||||
case AlbumType.download:
|
||||
return context.l10n.albumDownload;
|
||||
case AlbumType.screenshots:
|
||||
return context.l10n.albumScreenshots;
|
||||
case AlbumType.screenRecordings:
|
||||
return context.l10n.albumScreenRecordings;
|
||||
case AlbumType.videoCaptures:
|
||||
return context.l10n.albumVideoCaptures;
|
||||
case AlbumType.regular:
|
||||
case AlbumType.app:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final dir = VolumeRelativeDirectory.fromPath(dirPath);
|
||||
if (dir == null) return dirPath;
|
||||
|
||||
final relativeDir = dir.relativeDir;
|
||||
if (relativeDir.isEmpty) {
|
||||
final volume = androidFileUtils.getStorageVolume(dirPath)!;
|
||||
return volume.getDescription(context);
|
||||
}
|
||||
|
||||
String unique(String dirPath, Set<String?> others) {
|
||||
final parts = pContext.split(dirPath);
|
||||
for (var i = parts.length - 1; i > 0; i--) {
|
||||
final name = pContext.joinAll(['', ...parts.skip(i)]);
|
||||
final testName = '$separator$name';
|
||||
if (others.every((item) => !item!.endsWith(testName))) return name;
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
final otherAlbumsOnDevice = _directories.where((item) => item != dirPath).toSet();
|
||||
final uniqueNameInDevice = unique(dirPath, otherAlbumsOnDevice);
|
||||
if (uniqueNameInDevice.length <= relativeDir.length) {
|
||||
return uniqueNameInDevice;
|
||||
}
|
||||
|
||||
final volumePath = dir.volumePath;
|
||||
String trimVolumePath(String? path) => path!.substring(dir.volumePath.length);
|
||||
final otherAlbumsOnVolume = otherAlbumsOnDevice.where((path) => path!.startsWith(volumePath)).map(trimVolumePath).toSet();
|
||||
final uniqueNameInVolume = unique(trimVolumePath(dirPath), otherAlbumsOnVolume);
|
||||
final volume = androidFileUtils.getStorageVolume(dirPath)!;
|
||||
if (volume.isPrimary) {
|
||||
return uniqueNameInVolume;
|
||||
} else {
|
||||
return '$uniqueNameInVolume (${volume.getDescription(context)})';
|
||||
}
|
||||
}
|
||||
|
||||
String getAlbumDisplayName(BuildContext? context, String dirPath) {
|
||||
final names = (context != null ? _albumDisplayNamesWithContext : _albumDisplayNamesWithoutContext);
|
||||
return names.putIfAbsent(dirPath, () => _computeDisplayName(context, dirPath));
|
||||
}
|
||||
}
|
||||
|
||||
class AlbumsChangedEvent {}
|
||||
|
|
|
@ -68,7 +68,12 @@ class CollectionLens with ChangeNotifier {
|
|||
}));
|
||||
favourites.addListener(_onFavouritesChanged);
|
||||
}
|
||||
settings.addListener(_onSettingsChanged);
|
||||
_subscriptions.add(settings.updateStream
|
||||
.where([
|
||||
Settings.collectionSortFactorKey,
|
||||
Settings.collectionGroupFactorKey,
|
||||
].contains)
|
||||
.listen((_) => _onSettingsChanged()));
|
||||
_refresh();
|
||||
}
|
||||
|
||||
|
@ -78,7 +83,6 @@ class CollectionLens with ChangeNotifier {
|
|||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
favourites.removeListener(_onFavouritesChanged);
|
||||
settings.removeListener(_onSettingsChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ mixin SourceBase {
|
|||
}
|
||||
|
||||
abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagMixin {
|
||||
CollectionSource() {
|
||||
settings.updateStream.where((key) => key == Settings.localeKey).listen((_) => invalidateAlbumDisplayNames());
|
||||
}
|
||||
|
||||
final EventBus _eventBus = EventBus();
|
||||
|
||||
@override
|
||||
|
|
|
@ -50,6 +50,16 @@ class MediaStoreSource extends CollectionSource {
|
|||
stateNotifier.value = SourceState.loading;
|
||||
clearEntries();
|
||||
|
||||
final topIds = settings.topEntryIds;
|
||||
late final Set<AvesEntry> topEntries;
|
||||
if (topIds != null) {
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} load ${topIds.length} top entries');
|
||||
topEntries = await metadataDb.loadEntries(topIds);
|
||||
addEntries(topEntries);
|
||||
} else {
|
||||
topEntries = {};
|
||||
}
|
||||
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} fetch known entries');
|
||||
final oldEntries = await metadataDb.loadAllEntries();
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} check obsolete entries');
|
||||
|
@ -57,6 +67,11 @@ class MediaStoreSource extends CollectionSource {
|
|||
final obsoleteContentIds = (await mediaStoreService.checkObsoleteContentIds(knownDateById.keys.toList())).toSet();
|
||||
oldEntries.removeWhere((entry) => obsoleteContentIds.contains(entry.contentId));
|
||||
|
||||
if (topEntries.isNotEmpty) {
|
||||
final obsoleteTopEntries = topEntries.where((entry) => obsoleteContentIds.contains(entry.contentId));
|
||||
await removeEntries(obsoleteTopEntries.map((entry) => entry.uri).toSet());
|
||||
}
|
||||
|
||||
// show known entries
|
||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} add known entries');
|
||||
addEntries(oldEntries);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/db/db_metadata_sqflite.dart';
|
||||
import 'package:aves/model/settings/store/store.dart';
|
||||
import 'package:aves/model/settings/store/store_shared_pref.dart';
|
||||
import 'package:aves/services/android_app_service.dart';
|
||||
import 'package:aves/services/device_service.dart';
|
||||
import 'package:aves/services/media/embedded_data_service.dart';
|
||||
|
@ -19,6 +22,7 @@ final getIt = GetIt.instance;
|
|||
final p.Context pContext = getIt<p.Context>();
|
||||
final AvesAvailability availability = getIt<AvesAvailability>();
|
||||
final MetadataDb metadataDb = getIt<MetadataDb>();
|
||||
final SettingsStore settingsStore = getIt<SettingsStore>();
|
||||
|
||||
final AndroidAppService androidAppService = getIt<AndroidAppService>();
|
||||
final DeviceService deviceService = getIt<DeviceService>();
|
||||
|
@ -35,6 +39,7 @@ void initPlatformServices() {
|
|||
getIt.registerLazySingleton<p.Context>(p.Context.new);
|
||||
getIt.registerLazySingleton<AvesAvailability>(LiveAvesAvailability.new);
|
||||
getIt.registerLazySingleton<MetadataDb>(SqfliteMetadataDb.new);
|
||||
getIt.registerLazySingleton<SettingsStore>(SharedPrefSettingsStore.new);
|
||||
|
||||
getIt.registerLazySingleton<AndroidAppService>(PlatformAndroidAppService.new);
|
||||
getIt.registerLazySingleton<DeviceService>(PlatformDeviceService.new);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/app_flavor.dart';
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/l10n/l10n.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/screen_on.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/screen_on.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/media_store_source.dart';
|
||||
import 'package:aves/services/accessibility_service.dart';
|
||||
|
@ -16,12 +18,15 @@ import 'package:aves/theme/icons.dart';
|
|||
import 'package:aves/theme/themes.dart';
|
||||
import 'package:aves/utils/android_file_utils.dart';
|
||||
import 'package:aves/utils/debouncer.dart';
|
||||
import 'package:aves/widgets/collection/collection_grid.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/common/behaviour/route_tracker.dart';
|
||||
import 'package:aves/widgets/common/behaviour/routes.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
||||
import 'package:aves/widgets/home_page.dart';
|
||||
import 'package:aves/widgets/welcome_page.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -43,7 +48,7 @@ class AvesApp extends StatefulWidget {
|
|||
_AvesAppState createState() => _AvesAppState();
|
||||
}
|
||||
|
||||
class _AvesAppState extends State<AvesApp> {
|
||||
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||
final ValueNotifier<AppMode> appModeNotifier = ValueNotifier(AppMode.main);
|
||||
late Future<void> _appSetup;
|
||||
final _mediaStoreSource = MediaStoreSource();
|
||||
|
@ -70,6 +75,7 @@ class _AvesAppState extends State<AvesApp> {
|
|||
_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?));
|
||||
_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion());
|
||||
_errorChannel.receiveBroadcastStream().listen((event) => _onError(event as String?));
|
||||
WidgetsBinding.instance!.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -158,26 +164,45 @@ class _AvesAppState extends State<AvesApp> {
|
|||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
debugPrint('$runtimeType lifecycle ${state.name}');
|
||||
switch (state) {
|
||||
case AppLifecycleState.inactive:
|
||||
_saveTopEntries();
|
||||
break;
|
||||
case AppLifecycleState.paused:
|
||||
case AppLifecycleState.detached:
|
||||
case AppLifecycleState.resumed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save IDs of entries visible at the top of the collection page with current layout settings
|
||||
void _saveTopEntries() {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final screenSize = window.physicalSize / window.devicePixelRatio;
|
||||
var tileExtent = settings.getTileExtent(CollectionPage.routeName);
|
||||
if (tileExtent == 0) {
|
||||
tileExtent = screenSize.shortestSide / CollectionGrid.columnCountDefault;
|
||||
}
|
||||
final rows = (screenSize.height / tileExtent).ceil();
|
||||
final columns = (screenSize.width / tileExtent).ceil();
|
||||
final count = rows * columns;
|
||||
final collection = CollectionLens(source: _mediaStoreSource, listenToSource: false);
|
||||
settings.topEntryIds = collection.sortedEntries.take(count).map((entry) => entry.contentId).whereNotNull().toList();
|
||||
collection.dispose();
|
||||
debugPrint('Saved $count top entries in ${stopwatch.elapsed.inMilliseconds}ms');
|
||||
}
|
||||
|
||||
// setup before the first page is displayed. keep it short
|
||||
Future<void> _setup() async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
// TODO TLAD [init] init settings/device w/o platform calls (first platform channel call takes ~800ms):
|
||||
// 1) use cached values if any,
|
||||
// 2a) call platform w/ delay if cached
|
||||
// 2b) call platform w/o delay if not cached
|
||||
// 3) cache platform call results across app restarts
|
||||
|
||||
await device.init();
|
||||
final isRotationLocked = await windowService.isRotationLocked();
|
||||
final areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
|
||||
// TODO TLAD [init] migrate settings away from `shared_preferences` to a platform-free solution
|
||||
await settings.init(
|
||||
monitorPlatformSettings: true,
|
||||
isRotationLocked: isRotationLocked,
|
||||
areAnimationsRemoved: areAnimationsRemoved,
|
||||
);
|
||||
await settings.init(monitorPlatformSettings: true);
|
||||
settings.isRotationLocked = await windowService.isRotationLocked();
|
||||
settings.areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
_monitorSettings();
|
||||
|
||||
FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
|
@ -187,22 +212,30 @@ class _AvesAppState extends State<AvesApp> {
|
|||
}
|
||||
|
||||
void _monitorSettings() {
|
||||
// keep screen on
|
||||
settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen(
|
||||
(_) => settings.keepScreenOn.apply(),
|
||||
);
|
||||
settings.keepScreenOn.apply();
|
||||
void applyIsInstalledAppAccessAllowed() {
|
||||
if (settings.isInstalledAppAccessAllowed) {
|
||||
androidFileUtils.initAppNames();
|
||||
} else {
|
||||
androidFileUtils.resetAppNames();
|
||||
}
|
||||
}
|
||||
|
||||
// installed app access
|
||||
settings.updateStream.where((key) => key == Settings.isInstalledAppAccessAllowedKey).listen(
|
||||
(_) {
|
||||
if (settings.isInstalledAppAccessAllowed) {
|
||||
androidFileUtils.initAppNames();
|
||||
} else {
|
||||
androidFileUtils.resetAppNames();
|
||||
}
|
||||
},
|
||||
);
|
||||
void applyKeepScreenOn() {
|
||||
settings.keepScreenOn.apply();
|
||||
}
|
||||
|
||||
void applyIsRotationLocked() {
|
||||
if (!settings.isRotationLocked) {
|
||||
windowService.requestOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
settings.updateStream.where((key) => key == Settings.isInstalledAppAccessAllowedKey).listen((_) => applyIsInstalledAppAccessAllowed());
|
||||
settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen((_) => applyKeepScreenOn());
|
||||
settings.updateStream.where((key) => key == Settings.platformAccelerometerRotationKey).listen((_) => applyIsRotationLocked());
|
||||
|
||||
applyKeepScreenOn();
|
||||
applyIsRotationLocked();
|
||||
}
|
||||
|
||||
Future<void> _setupErrorReporting() async {
|
||||
|
|
|
@ -39,6 +39,11 @@ import 'package:tuple/tuple.dart';
|
|||
class CollectionGrid extends StatefulWidget {
|
||||
final String? settingsRouteKey;
|
||||
|
||||
static const int columnCountDefault = 4;
|
||||
static const double extentMin = 46;
|
||||
static const double extentMax = 300;
|
||||
static const double spacing = 2;
|
||||
|
||||
const CollectionGrid({
|
||||
Key? key,
|
||||
this.settingsRouteKey,
|
||||
|
@ -61,9 +66,10 @@ class _CollectionGridState extends State<CollectionGrid> {
|
|||
Widget build(BuildContext context) {
|
||||
_tileExtentController ??= TileExtentController(
|
||||
settingsRouteKey: widget.settingsRouteKey ?? context.currentRouteName!,
|
||||
columnCountDefault: 4,
|
||||
extentMin: 46,
|
||||
spacing: 2,
|
||||
columnCountDefault: CollectionGrid.columnCountDefault,
|
||||
extentMin: CollectionGrid.extentMin,
|
||||
extentMax: CollectionGrid.extentMax,
|
||||
spacing: CollectionGrid.spacing,
|
||||
);
|
||||
return TileExtentControllerProvider(
|
||||
controller: _tileExtentController!,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/accessibility_service.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/model/filters/album.dart';
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/filters/tag.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/viewer/info/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/filters/coordinate.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:async';
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
import 'package:aves/widgets/common/map/buttons.dart';
|
||||
import 'package:aves/widgets/common/map/controller.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/utils/debouncer.dart';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/widgets/common/basic/outlined_text.dart';
|
||||
import 'package:aves/widgets/common/map/leaflet/scalebar_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -4,9 +4,9 @@ import 'dart:ui';
|
|||
import 'package:aves/image_providers/thumbnail_provider.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/widgets/common/fx/checkered_decoration.dart';
|
||||
|
|
|
@ -20,7 +20,7 @@ class TileExtentController {
|
|||
this.columnCountMin = 2,
|
||||
required this.columnCountDefault,
|
||||
required this.extentMin,
|
||||
this.extentMax = 300,
|
||||
required this.extentMax,
|
||||
required this.spacing,
|
||||
}) {
|
||||
userPreferredExtent = settings.getTileExtent(settingsRouteKey);
|
||||
|
|
|
@ -68,6 +68,7 @@ class DebugSettingsSection extends StatelessWidget {
|
|||
'searchHistory': toMultiline(settings.searchHistory),
|
||||
'locale': '${settings.locale}',
|
||||
'systemLocales': '${WidgetsBinding.instance!.window.locales}',
|
||||
'topEntryIds': '${settings.topEntryIds}',
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
|
|
@ -164,6 +164,7 @@ class _FilterGridState<T extends CollectionFilter> extends State<FilterGrid<T>>
|
|||
settingsRouteKey: widget.settingsRouteKey ?? context.currentRouteName!,
|
||||
columnCountDefault: 3,
|
||||
extentMin: 60,
|
||||
extentMax: 300,
|
||||
spacing: 8,
|
||||
);
|
||||
return TileExtentControllerProvider(
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/app_mode.dart';
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/home_page.dart';
|
||||
import 'package:aves/model/settings/enums/home_page.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/geocoding_service.dart';
|
||||
|
|
|
@ -4,8 +4,8 @@ import 'package:aves/model/entry.dart';
|
|||
import 'package:aves/model/filters/coordinate.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/settings/accessibility_timeout.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_timeout.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/accessibility_service.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/settings/unit_system.dart';
|
||||
import 'package:aves/model/settings/enums/unit_system.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/color_utils.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/home_page.dart';
|
||||
import 'package:aves/model/settings/screen_on.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/enums/home_page.dart';
|
||||
import 'package:aves/model/settings/enums/screen_on.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/color_utils.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:aves/model/filters/mime.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/settings/video_loop_mode.dart';
|
||||
import 'package:aves/model/settings/enums/video_loop_mode.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/color_utils.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/settings/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/widgets/common/fx/borders.dart';
|
||||
import 'package:aves/widgets/common/fx/checkered_decoration.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:aves/model/filters/location.dart';
|
|||
import 'package:aves/model/filters/mime.dart';
|
||||
import 'package:aves/model/filters/rating.dart';
|
||||
import 'package:aves/model/filters/tag.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/widgets/common/magnifier/pan/gesture_detector_scope.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/model/device.dart';
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/metadata/overlay.dart';
|
||||
import 'package:aves/model/multipage.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:typed_data';
|
|||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/settings/video_loop_mode.dart';
|
||||
import 'package:aves/model/settings/enums/video_loop_mode.dart';
|
||||
import 'package:aves/model/video/keys.dart';
|
||||
import 'package:aves/model/video/metadata.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/enums/accessibility_animations.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/widgets/common/magnifier/controller/controller.dart';
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'dart:math';
|
|||
import 'package:aves/image_providers/region_provider.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/utils/math_utils.dart';
|
||||
import 'package:aves/widgets/common/fx/checkered_decoration.dart';
|
||||
|
|
|
@ -4,8 +4,8 @@ import 'dart:ui';
|
|||
import 'package:aves/image_providers/region_provider.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/entry_background.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/utils/math_utils.dart';
|
||||
import 'package:aves/widgets/common/fx/checkered_decoration.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/model/favourites.dart';
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/metadata/address.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:aves/model/filters/album.dart';
|
|||
import 'package:aves/model/filters/tag.dart';
|
||||
import 'package:aves/model/metadata/address.dart';
|
||||
import 'package:aves/model/metadata/catalog.dart';
|
||||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:aves/model/db/db_metadata.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/enums.dart';
|
||||
import 'package:aves/model/source/media_store_source.dart';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/l10n/l10n.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/utils/geo_utils.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/main_play.dart' as app;
|
||||
import 'package:aves/model/settings/defaults.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/enums.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/main_play.dart' as app;
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
|
Loading…
Reference in a new issue