diff --git a/example/lib/screens/import_store/import_store.dart b/example/lib/screens/import_store/import_store.dart index 44c78815..c8ecec2e 100644 --- a/example/lib/screens/import_store/import_store.dart +++ b/example/lib/screens/import_store/import_store.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; -import 'package:fmtc_plus_sharing/fmtc_plus_sharing.dart'; +//import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; +//import 'package:fmtc_plus_sharing/fmtc_plus_sharing.dart'; class ImportStorePopup extends StatefulWidget { const ImportStorePopup({super.key}); @@ -14,14 +14,15 @@ class ImportStorePopup extends StatefulWidget { class _ImportStorePopupState extends State { final Map importStores = {}; +// TODO: Implement @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( title: const Text('Import Stores'), ), - body: Padding( - padding: const EdgeInsets.all(12), - child: ListView.separated( + body: const Padding( + padding: EdgeInsets.all(12), + /*child: ListView.separated( itemCount: importStores.length + 1, itemBuilder: (context, i) { if (i == importStores.length) { @@ -30,7 +31,7 @@ class _ImportStorePopupState extends State { title: const Text('Choose New Store(s)'), subtitle: const Text('Select any valid store files (.fmtc)'), onTap: () async { - importStores.addAll( + /*importStores.addAll( (await FMTCRoot.import.withGUI( collisionHandler: (fn, sn) { setState( @@ -51,7 +52,8 @@ class _ImportStorePopupState extends State { _ImportStore(status, collisionInfo: null), ), ), - ); + );*/ + if (mounted) setState(() {}); }, ); @@ -131,13 +133,13 @@ class _ImportStorePopupState extends State { separatorBuilder: (context, i) => i == importStores.length - 1 ? const Divider() : const SizedBox.shrink(), - ), + ),*/ ), ); } class _ImportStore { - final Future result; + final Future result; List? collisionInfo; Completer collisionResolution; diff --git a/example/lib/screens/main/main.dart b/example/lib/screens/main/main.dart index e37b0aa5..9abedda4 100644 --- a/example/lib/screens/main/main.dart +++ b/example/lib/screens/main/main.dart @@ -41,7 +41,7 @@ class _MainScreenState extends State { NavigationDestination( label: 'Recover', icon: StreamBuilder( - stream: FMTCRoot.stats.watchChanges().asBroadcastStream(), + stream: FMTCRoot.stats.watchRecovery(), builder: (context, _) => FutureBuilder( future: FMTCRoot.recovery.recoverableRegions, builder: (context, snapshot) => Badge( diff --git a/example/lib/screens/main/pages/recovery/recovery.dart b/example/lib/screens/main/pages/recovery/recovery.dart index c09e263a..e8212d35 100644 --- a/example/lib/screens/main/pages/recovery/recovery.dart +++ b/example/lib/screens/main/pages/recovery/recovery.dart @@ -30,7 +30,7 @@ class _RecoveryPageState extends State { _recoverableRegions = FMTCRoot.recovery.recoverableRegions; listRecoverableRegions(); - FMTCRoot.stats.watchChanges(watchRecovery: true).listen((_) { + FMTCRoot.stats.watchRecovery().listen((_) { if (mounted) { listRecoverableRegions(); setState(() {}); diff --git a/example/lib/screens/main/pages/stores/components/store_tile.dart b/example/lib/screens/main/pages/stores/components/store_tile.dart index 1a3f5ce8..675bf199 100644 --- a/example/lib/screens/main/pages/stores/components/store_tile.dart +++ b/example/lib/screens/main/pages/stores/components/store_tile.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; -import 'package:fmtc_plus_sharing/fmtc_plus_sharing.dart'; import 'package:provider/provider.dart'; import '../../../../../shared/misc/exts/size_formatter.dart'; @@ -207,7 +206,8 @@ class _StoreTileState extends State { onPressed: _exportingProgress ? null : () async { - setState( + // TODO: Implement + /* setState( () => _exportingProgress = true, ); final bool result = await _store @@ -228,7 +228,7 @@ class _StoreTileState extends State { ), ), ); - } + }*/ }, ), IconButton( diff --git a/example/lib/screens/main/pages/stores/stores.dart b/example/lib/screens/main/pages/stores/stores.dart index 7f34dd60..24741da7 100644 --- a/example/lib/screens/main/pages/stores/stores.dart +++ b/example/lib/screens/main/pages/stores/stores.dart @@ -26,7 +26,7 @@ class _StoresPageState extends State { void listStores() => _stores = FMTCRoot.stats.storesAvailable; listStores(); - FMTCRoot.stats.watchChanges().listen((_) { + FMTCRoot.stats.watchStores().listen((_) { if (mounted) { listStores(); setState(() {}); @@ -48,7 +48,8 @@ class _StoresPageState extends State { child: FutureBuilder>( future: _stores, builder: (context, snapshot) => snapshot.hasError - ? throw snapshot.error! as FMTCDamagedStoreException + // ignore: only_throw_errors + ? throw snapshot.error! : snapshot.hasData ? snapshot.data!.isEmpty ? const EmptyIndicator() diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8d9ec7c6..b9b21a12 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: flutter_map_animations: ^0.5.3 flutter_map_tile_caching: ^9.0.0-dev.5 flutter_speed_dial: ^7.0.0 - fmtc_plus_sharing: ^8.0.0 + #fmtc_plus_sharing: ^8.0.0 google_fonts: ^6.1.0 gpx: ^2.2.1 http: ^1.1.2 diff --git a/example/windows/flutter/CMakeLists.txt b/example/windows/flutter/CMakeLists.txt index 930d2071..903f4899 100644 --- a/example/windows/flutter/CMakeLists.txt +++ b/example/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index 8700c13c..a84779d7 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -6,18 +6,9 @@ #include "generated_plugin_registrant.h" -#include #include -#include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { - IsarFlutterLibsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); ObjectboxFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ObjectboxFlutterLibsPlugin")); - SharePlusWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); - UrlLauncherWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index 57dfe6f1..9f0138ed 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -3,10 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST - isar_flutter_libs objectbox_flutter_libs - share_plus - url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/lib/flutter_map_tile_caching.dart b/lib/flutter_map_tile_caching.dart index b2617b69..c81e65c6 100644 --- a/lib/flutter_map_tile_caching.dart +++ b/lib/flutter_map_tile_caching.dart @@ -45,7 +45,6 @@ part 'src/bulk_download/download_progress.dart'; part 'src/bulk_download/manager.dart'; part 'src/bulk_download/thread.dart'; part 'src/bulk_download/tile_event.dart'; -part 'src/fmtc.dart'; part 'src/misc/deprecations.dart'; part 'src/providers/tile_provider.dart'; part 'src/regions/base_region.dart'; diff --git a/lib/src/backend/impls/objectbox/backend.dart b/lib/src/backend/impls/objectbox/backend.dart index 0579e02d..bb039c57 100644 --- a/lib/src/backend/impls/objectbox/backend.dart +++ b/lib/src/backend/impls/objectbox/backend.dart @@ -8,8 +8,6 @@ import 'dart:isolate'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter_map/flutter_map.dart'; -import 'package:latlong2/latlong.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; @@ -103,14 +101,7 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal { _sendPort!.send((id: id, type: type, args: args)); final res = await _workerRes[id]!.future; _workerRes.remove(id); - - final err = res?['error']; - if (err == null) return res; - - if (err is FMTCBackendError) throw err; - debugPrint('An unexpected error in the FMTC backend occurred:'); - // ignore: only_throw_errors - throw err; + return res; } Future initialise({ @@ -146,6 +137,22 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal { _workerHandler = receivePort.listen( (evt) { evt as ({int id, Map? data}); + + final err = evt.data?['error']; + if (err != null) { + if (err is FMTCBackendError) throw err; + + debugPrint('An unexpected error in the FMTC backend occurred:'); + if (err is Error) { + debugPrint(err.stackTrace.toString()); + throw err; + } else { + debugPrint( + 'But it was not of type `Error`, it was type ${err.runtimeType}', + ); + } + } + _workerRes[evt.id]!.complete(evt.data); }, onDone: () => _workerComplete.complete(), @@ -482,4 +489,26 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal { required int id, }) => _sendCmd(type: _WorkerCmdType.cancelRecovery, args: {'id': id}); + + @override + Future> watchRecovery({ + required bool triggerImmediately, + }) async => + (await _sendCmd( + type: _WorkerCmdType.watchRecovery, + args: {'triggerImmediately': triggerImmediately}, + ))!['stream']; + + @override + Future> watchStores({ + required List storeNames, + required bool triggerImmediately, + }) async => + (await _sendCmd( + type: _WorkerCmdType.watchStores, + args: { + 'storeNames': storeNames, + 'triggerImmediately': triggerImmediately, + }, + ))!['stream']; } diff --git a/lib/src/backend/impls/objectbox/models/src/recovery.dart b/lib/src/backend/impls/objectbox/models/src/recovery.dart index 96cb5645..bd888336 100644 --- a/lib/src/backend/impls/objectbox/models/src/recovery.dart +++ b/lib/src/backend/impls/objectbox/models/src/recovery.dart @@ -1,6 +1,8 @@ // Copyright © Luka S (JaffaKetchup) under GPL-v3 // A full license can be found at .\LICENSE +import 'package:flutter_map/flutter_map.dart'; +import 'package:latlong2/latlong.dart'; import 'package:meta/meta.dart'; import 'package:objectbox/objectbox.dart'; @@ -66,7 +68,7 @@ base class ObjectBoxRecovery { required this.customPolygonLngs, }); - ObjectBoxRecovery.startFromRegion({ + ObjectBoxRecovery.fromRegion({ required this.refId, required this.storeName, required DownloadableRegion region, @@ -141,4 +143,32 @@ base class ObjectBoxRecovery { .map((c) => c.longitude) .toList() : null; + + RecoveredRegion toRegion() => RecoveredRegion( + id: id, + storeName: storeName, + time: creationTime, + bounds: typeId == 0 + ? LatLngBounds( + LatLng(rectNwLat!, rectNwLng!), + LatLng(rectSeLat!, rectSeLng!), + ) + : null, + center: typeId == 1 ? LatLng(circleCenterLat!, circleCenterLng!) : null, + line: typeId == 2 || typeId == 3 + ? List.generate( + lineLats!.length, + (i) => LatLng(lineLats![i], lineLngs![i]), + ) + : null, + radius: typeId == 1 + ? circleRadius! + : typeId == 2 + ? lineRadius! + : null, + minZoom: minZoom, + maxZoom: maxZoom, + start: startTile, + end: endTile, + ); } diff --git a/lib/src/backend/impls/objectbox/worker.dart b/lib/src/backend/impls/objectbox/worker.dart index 631c1dee..12015ee8 100644 --- a/lib/src/backend/impls/objectbox/worker.dart +++ b/lib/src/backend/impls/objectbox/worker.dart @@ -33,6 +33,8 @@ enum _WorkerCmdType { getRecoverableRegion, startRecovery, cancelRecovery, + watchRecovery, + watchStores, } Future _worker( @@ -811,37 +813,10 @@ Future _worker( sendRes( id: cmd.id, data: { - 'recoverableRegions': root.box().getAll().map( - (r) => RecoveredRegion( - id: r.id, - storeName: r.storeName, - time: r.creationTime, - bounds: r.typeId == 0 - ? LatLngBounds( - LatLng(r.rectNwLat!, r.rectNwLng!), - LatLng(r.rectSeLat!, r.rectSeLng!), - ) - : null, - center: r.typeId == 1 - ? LatLng(r.circleCenterLat!, r.circleCenterLng!) - : null, - line: r.typeId == 2 || r.typeId == 3 - ? List.generate( - r.lineLats!.length, - (i) => LatLng(r.lineLats![i], r.lineLngs![i]), - ) - : null, - radius: r.typeId == 1 - ? r.circleRadius! - : r.typeId == 2 - ? r.lineRadius! - : null, - minZoom: r.minZoom, - maxZoom: r.maxZoom, - start: r.startTile, - end: r.endTile, - ), - ), + 'recoverableRegions': root + .box() + .getAll() + .map((r) => r.toRegion()), }, ); @@ -849,14 +824,18 @@ Future _worker( case _WorkerCmdType.getRecoverableRegion: final id = cmd.args['id']! as int; - final query = root - .box() - .query(ObjectBoxRecovery_.refId.equals(id)) - .build(); - - sendRes(id: cmd.id, data: {'recoverableRegion': query.findUnique()}); - - query.close(); + sendRes( + id: cmd.id, + data: { + 'recoverableRegion': (root + .box() + .query(ObjectBoxRecovery_.refId.equals(id)) + .build() + ..close()) + .findUnique() + ?.toRegion(), + }, + ); break; case _WorkerCmdType.startRecovery: @@ -865,7 +844,7 @@ Future _worker( final region = cmd.args['region']! as DownloadableRegion; root.box().put( - ObjectBoxRecovery.startFromRegion( + ObjectBoxRecovery.fromRegion( refId: id, storeName: storeName, region: region, @@ -885,6 +864,39 @@ Future _worker( sendRes(id: cmd.id); + break; + case _WorkerCmdType.watchRecovery: + final triggerImmediately = cmd.args['triggerImmediately']! as bool; + + sendRes( + id: cmd.id, + data: { + 'stream': root + .box() + .query() + .watch(triggerImmediately: triggerImmediately), + }, + ); + + break; + case _WorkerCmdType.watchStores: + final storeNames = cmd.args['storeNames']! as List; + final triggerImmediately = cmd.args['triggerImmediately']! as bool; + + sendRes( + id: cmd.id, + data: { + 'stream': root + .box() + .query( + storeNames.isEmpty + ? null + : ObjectBoxStore_.name.oneOf(storeNames), + ) + .watch(triggerImmediately: triggerImmediately), + }, + ); + break; } } catch (e) { diff --git a/lib/src/backend/interfaces/backend.dart b/lib/src/backend/interfaces/backend.dart index 0e632ed9..8e1ff881 100644 --- a/lib/src/backend/interfaces/backend.dart +++ b/lib/src/backend/interfaces/backend.dart @@ -321,4 +321,31 @@ abstract interface class FMTCBackendInternal with FMTCBackendAccess { Future cancelRecovery({ required int id, }); + + /// {@template fmtc.backend.watchRecovery} + /// Watch for changes to the recovery system + /// + /// Useful to update UI only when required, for example, in a `StreamBuilder`. + /// Whenever this has an event, it is likely the other statistics will have + /// changed. + /// {@endtemplate} + Future> watchRecovery({ + required bool triggerImmediately, + }); + + /// {@template fmtc.backend.watchStores} + /// Watch for changes in the specified stores, or all stores if no stores + /// are provided + /// + /// Useful to update UI only when required, for example, in a `StreamBuilder`. + /// Whenever this has an event, it is likely the other statistics will have + /// changed. + /// + /// Emits an event every time a change is made to a store (every time a + /// statistic changes, which should include every time a tile is changed). + /// {@endtemplate} + Future> watchStores({ + required List storeNames, + required bool triggerImmediately, + }); } diff --git a/lib/src/fmtc.dart b/lib/src/fmtc.dart deleted file mode 100644 index 2ed03343..00000000 --- a/lib/src/fmtc.dart +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright © Luka S (JaffaKetchup) under GPL-v3 -// A full license can be found at .\LICENSE - -part of flutter_map_tile_caching; - -/*/// Direct alias of [FlutterMapTileCaching] for easier development -/// -/// Prefer use of full 'FlutterMapTileCaching' when initialising to ensure -/// readability and understanding in other code. -typedef FMTC = FlutterMapTileCaching; - -/// Main singleton access point for 'flutter_map_tile_caching' -/// -/// You must construct using [FlutterMapTileCaching.initialise] before using -/// [FlutterMapTileCaching.instance], otherwise a [StateError] will be thrown. -/// Note that the singleton can be re-initialised/changed by calling the -/// aforementioned constructor again. -/// -/// [FMTC] is an alias for this object. -class FlutterMapTileCaching { - /// The directory which contains all databases required to use FMTC - final FMTCRoot rootDirectory; - - /// The database or other storage mechanism that FMTC will use as a cache - /// 'backend' - /// - /// Defaults to [ObjectBoxBackend], which uses the ObjectBox library and - /// database. - /// - /// See [FMTCBackend] for more information. - final FMTCBackend backend; - - /// Default settings used when creating an [FMTCTileProvider] - /// - /// Can be overridden on a case-to-case basis when actually creating the tile - /// provider. - final FMTCTileProviderSettings defaultTileProviderSettings; - - /// Internal constructor, to be used by [initialise] - const FlutterMapTileCaching._({ - required this.rootDirectory, - required this.backend, - required this.defaultTileProviderSettings, - }); - - /// Initialise and prepare FMTC, by creating all necessary directories/files - /// and configuring the [FlutterMapTileCaching] singleton - /// - /// You must construct using this before using [FlutterMapTileCaching.instance], - /// otherwise a [StateError] will be thrown. - /// - /// Returns a configured [FlutterMapTileCaching] instance, and assigns it to - /// [instance]. - /// - /// Note that [FMTC] is an alias for [FlutterMapTileCaching]. - /// - /// --- - /// - /// Prefer to leave [rootDirectory] as `null`, which will use - /// `getApplicationDocumentsDirectory()`. Alternatively, pass a custom - /// directory - it is recommended to not use a cache directory, as the OS can - /// clear these without notice at any time. - /// - /// Optionally set a custom storage [backend] instead of [ObjectBoxBackend]. - /// Some implementations may accept/require additional arguments that may be - /// set through [backendImplArgs]. See their documentation for more - /// information. If provided, they must be of the specified type. - /// - /// > The default [ObjectBoxBackend] accepts the following optional - /// > [backendImplArgs] (note that other implementations may support different - /// > args). For ease of use, they have been provided in this method as typed - /// > arguments - these may be useless in other implementations (although they - /// > will be forwarded to any). - /// > - /// > * [macosApplicationGroup] : when creating a sandboxed macOS app, - /// > use to specify the application group (of less than 20 chars). See - /// > [the ObjectBox docs](https://docs.objectbox.io/getting-started) for - /// > details. - /// > * [maxDatabaseSize] : the maximum size the database file can grow - /// > to. Exceeding it throws `DbFullException`. Defaults to 10 GB. - static Future initialise({ - String? rootDirectory, - FMTCBackend? backend, - Map backendImplArgs = const {}, - String? macosApplicationGroup, - int? maxDatabaseSize, - FMTCTileProviderSettings? defaultTileProviderSettings, - }) async { - final dir = await (rootDirectory == null - ? await getApplicationDocumentsDirectory() - : Directory(rootDirectory) >> 'fmtc') - .create(recursive: true); - - backend ??= ObjectBoxBackend(); - - await backend.internal.initialise( - rootDirectory: dir, - implSpecificArgs: { - if (macosApplicationGroup != null) - 'macosApplicationGroup': macosApplicationGroup, - if (maxDatabaseSize != null) 'maxDatabaseSize': maxDatabaseSize, - }..addAll(backendImplArgs), - ); - - return _instance = FMTC._( - rootDirectory: FMTCRoot._(dir), - backend: backend, - defaultTileProviderSettings: - defaultTileProviderSettings ?? FMTCTileProviderSettings(), - ); - } - - /// Get the configured instance of [FlutterMapTileCaching], after - /// [FlutterMapTileCaching.initialise] has been called, for further actions - static FlutterMapTileCaching get instance => - _instance ?? - (throw StateError( - ''' -Use `FlutterMapTileCaching.initialise()` before getting -`FlutterMapTileCaching.instance` (or a method which requires an instance). - ''', - )); - static FlutterMapTileCaching? _instance; - - /// Construct a [FMTCStore] by name - /// - /// {@macro fmtc.fmtcstore.sub.noautocreate} - /// - /// Equivalent to constructing the [FMTCStore] directly. This method is - /// provided for backwards-compatibility. - FMTCStore call(String storeName) => FMTCStore(storeName); -} -*/ \ No newline at end of file diff --git a/lib/src/root/statistics.dart b/lib/src/root/statistics.dart index 621665bf..97be41d7 100644 --- a/lib/src/root/statistics.dart +++ b/lib/src/root/statistics.dart @@ -17,39 +17,25 @@ class RootStats { /// {@macro fmtc.backend.rootLength} Future get rootLength async => FMTCBackendAccess.internal.rootLength(); - /// Watch for changes in the current root - /// - /// Useful to update UI only when required, for example, in a `StreamBuilder`. - /// Whenever this has an event, it is likely the other statistics will have - /// changed. - /// - /// Recursively watch specific stores (using [StoreStats.watchChanges]) by - /// providing them as a list of [FMTCStore]s to [recursive]. To watch all - /// stores, use the [storesAvailable]/[storesAvailableAsync] getter as the - /// argument. By default, no sub-stores are watched (empty list), meaning only - /// events that affect the actual store database (eg. store creations) will be - /// caught. Control where changes are caught from using [storeParts]. See - /// documentation on those parts for their scope. - /// - /// Enable debouncing to prevent unnecessary events for small changes in detail - /// using [debounce]. Defaults to 200ms, or set to null to disable debouncing. - /// - /// Debouncing example (dash roughly represents [debounce]): - /// ```dart - /// input: 1-2-3---4---5-6-| - /// output: ------3---4-----6| - /// ``` - Stream watchChanges({ - Duration? debounce = const Duration(milliseconds: 200), - bool fireImmediately = false, - List recursive = const [], - bool watchRecovery = false, - List storeParts = const [ - StoreParts.metadata, - StoreParts.tiles, - StoreParts.stats, - ], - }) => - // TODO: Implement - throw UnimplementedError(); + /// {@macro fmtc.backend.watchRecovery} + Stream watchRecovery({ + bool triggerImmediately = false, + }) async* { + final stream = await FMTCBackendAccess.internal.watchRecovery( + triggerImmediately: triggerImmediately, + ); + yield* stream; + } + + /// {@macro fmtc.backend.watchStores} + Stream watchStores({ + List storeNames = const [], + bool triggerImmediately = false, + }) async* { + final stream = await FMTCBackendAccess.internal.watchStores( + storeNames: storeNames, + triggerImmediately: triggerImmediately, + ); + yield* stream; + } } diff --git a/lib/src/store/statistics.dart b/lib/src/store/statistics.dart index 7718b24f..50155064 100644 --- a/lib/src/store/statistics.dart +++ b/lib/src/store/statistics.dart @@ -45,46 +45,14 @@ class StoreStats { /// {@macro fmtc.frontend.storestats.efficiency} Future get misses => all.then((a) => a.misses); - /// Watch for changes in the current store - /// - /// Useful to update UI only when required, for example, in a `StreamBuilder`. - /// Whenever this has an event, it is likely the other statistics will have - /// changed. - /// - /// Control where changes are caught from using [storeParts]. See documentation - /// on those parts for their scope. - /// - /// Enable debouncing to prevent unnecessary events for small changes in detail - /// using [debounce]. Defaults to 200ms, or set to null to disable debouncing. - /// - /// Debouncing example (dash roughly represents [debounce]): - /// ```dart - /// input: 1-2-3---4---5-6-| - /// output: ------3---4-----6| - /// ``` + /// {@macro fmtc.backend.watchStores} Stream watchChanges({ - Duration? debounce = const Duration(milliseconds: 200), - bool fireImmediately = false, - List storeParts = const [ - StoreParts.metadata, - StoreParts.tiles, - StoreParts.stats, - ], - }) => - // TODO: Implement - throw UnimplementedError(); -} - -/// Parts of a store which can be watched -enum StoreParts { - /// Include changes to the store's metadata objects - metadata, - - /// Includes changes to the store's tile objects, including those which will - /// make some statistics change (eg. store size) - tiles, - - /// Includes changes to the store's descriptor object, which will change with - /// the cache hit and miss statistics - stats, + bool triggerImmediately = false, + }) async* { + final stream = await FMTCBackendAccess.internal.watchStores( + storeNames: [_storeName], + triggerImmediately: triggerImmediately, + ); + yield* stream; + } }