add basic routing options, auto update routing assets,use ruleset, remove geo assets
This commit is contained in:
@@ -1,32 +1,32 @@
|
||||
import 'package:hiddify/core/database/database_provider.dart';
|
||||
import 'package:hiddify/core/directories/directories_provider.dart';
|
||||
import 'package:hiddify/core/http_client/http_client_provider.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_source.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_repository.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
// import 'package:hiddify/core/database/database_provider.dart';
|
||||
// import 'package:hiddify/core/directories/directories_provider.dart';
|
||||
// import 'package:hiddify/core/http_client/http_client_provider.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_data_source.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_repository.dart';
|
||||
// import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'geo_asset_data_providers.g.dart';
|
||||
// part 'geo_asset_data_providers.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<GeoAssetRepository> geoAssetRepository(GeoAssetRepositoryRef ref) async {
|
||||
final repo = GeoAssetRepositoryImpl(
|
||||
geoAssetDataSource: ref.watch(geoAssetDataSourceProvider),
|
||||
geoAssetPathResolver: ref.watch(geoAssetPathResolverProvider),
|
||||
httpClient: ref.watch(httpClientProvider),
|
||||
);
|
||||
await repo.init().getOrElse((l) => throw l).run();
|
||||
return repo;
|
||||
}
|
||||
// @Riverpod(keepAlive: true)
|
||||
// Future<GeoAssetRepository> geoAssetRepository(GeoAssetRepositoryRef ref) async {
|
||||
// final repo = GeoAssetRepositoryImpl(
|
||||
// geoAssetDataSource: ref.watch(geoAssetDataSourceProvider),
|
||||
// geoAssetPathResolver: ref.watch(geoAssetPathResolverProvider),
|
||||
// httpClient: ref.watch(httpClientProvider),
|
||||
// );
|
||||
// await repo.init().getOrElse((l) => throw l).run();
|
||||
// return repo;
|
||||
// }
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
GeoAssetDataSource geoAssetDataSource(GeoAssetDataSourceRef ref) {
|
||||
return GeoAssetsDao(ref.watch(appDatabaseProvider));
|
||||
}
|
||||
// @Riverpod(keepAlive: true)
|
||||
// GeoAssetDataSource geoAssetDataSource(GeoAssetDataSourceRef ref) {
|
||||
// return GeoAssetsDao(ref.watch(appDatabaseProvider));
|
||||
// }
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
GeoAssetPathResolver geoAssetPathResolver(GeoAssetPathResolverRef ref) {
|
||||
return GeoAssetPathResolver(
|
||||
ref.watch(appDirectoriesProvider).requireValue.workingDir,
|
||||
);
|
||||
}
|
||||
// @Riverpod(keepAlive: true)
|
||||
// GeoAssetPathResolver geoAssetPathResolver(GeoAssetPathResolverRef ref) {
|
||||
// return GeoAssetPathResolver(
|
||||
// ref.watch(appDirectoriesProvider).requireValue.workingDir,
|
||||
// );
|
||||
// }
|
||||
|
||||
@@ -1,232 +1,232 @@
|
||||
import 'dart:io';
|
||||
// import 'dart:io';
|
||||
|
||||
import 'package:dartx/dartx_io.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/database/app_database.dart';
|
||||
import 'package:hiddify/core/http_client/dio_http_client.dart';
|
||||
import 'package:hiddify/core/utils/exception_handler.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_mapper.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_source.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/default_geo_assets.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_failure.dart';
|
||||
import 'package:hiddify/gen/assets.gen.dart';
|
||||
import 'package:hiddify/utils/custom_loggers.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:watcher/watcher.dart';
|
||||
// import 'package:dartx/dartx_io.dart';
|
||||
// import 'package:drift/drift.dart';
|
||||
// import 'package:flutter/services.dart';
|
||||
// import 'package:fpdart/fpdart.dart';
|
||||
// import 'package:hiddify/core/database/app_database.dart';
|
||||
// import 'package:hiddify/core/http_client/dio_http_client.dart';
|
||||
// import 'package:hiddify/core/utils/exception_handler.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_data_mapper.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_data_source.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/default_geo_assets.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_failure.dart';
|
||||
// import 'package:hiddify/gen/assets.gen.dart';
|
||||
// import 'package:hiddify/utils/custom_loggers.dart';
|
||||
// import 'package:rxdart/rxdart.dart';
|
||||
// import 'package:watcher/watcher.dart';
|
||||
|
||||
abstract interface class GeoAssetRepository {
|
||||
/// populate bundled geo assets directory with bundled files if needed
|
||||
TaskEither<GeoAssetFailure, Unit> init();
|
||||
TaskEither<GeoAssetFailure, ({GeoAssetEntity geoip, GeoAssetEntity geosite})>
|
||||
getActivePair();
|
||||
Stream<Either<GeoAssetFailure, List<GeoAssetWithFileSize>>> watchAll();
|
||||
TaskEither<GeoAssetFailure, Unit> update(GeoAssetEntity geoAsset);
|
||||
TaskEither<GeoAssetFailure, Unit> markAsActive(GeoAssetEntity geoAsset);
|
||||
TaskEither<GeoAssetFailure, Unit> addRecommended();
|
||||
}
|
||||
// abstract interface class GeoAssetRepository {
|
||||
// /// populate bundled geo assets directory with bundled files if needed
|
||||
// TaskEither<GeoAssetFailure, Unit> init();
|
||||
// TaskEither<GeoAssetFailure, ({GeoAssetEntity geoip, GeoAssetEntity geosite})>
|
||||
// getActivePair();
|
||||
// Stream<Either<GeoAssetFailure, List<GeoAssetWithFileSize>>> watchAll();
|
||||
// TaskEither<GeoAssetFailure, Unit> update(GeoAssetEntity geoAsset);
|
||||
// TaskEither<GeoAssetFailure, Unit> markAsActive(GeoAssetEntity geoAsset);
|
||||
// TaskEither<GeoAssetFailure, Unit> addRecommended();
|
||||
// }
|
||||
|
||||
class GeoAssetRepositoryImpl
|
||||
with ExceptionHandler, InfraLogger
|
||||
implements GeoAssetRepository {
|
||||
GeoAssetRepositoryImpl({
|
||||
required this.geoAssetDataSource,
|
||||
required this.geoAssetPathResolver,
|
||||
required this.httpClient,
|
||||
});
|
||||
// class GeoAssetRepositoryImpl
|
||||
// with ExceptionHandler, InfraLogger
|
||||
// implements GeoAssetRepository {
|
||||
// GeoAssetRepositoryImpl({
|
||||
// required this.geoAssetDataSource,
|
||||
// required this.geoAssetPathResolver,
|
||||
// required this.httpClient,
|
||||
// });
|
||||
|
||||
final GeoAssetDataSource geoAssetDataSource;
|
||||
final GeoAssetPathResolver geoAssetPathResolver;
|
||||
final DioHttpClient httpClient;
|
||||
// final GeoAssetDataSource geoAssetDataSource;
|
||||
// final GeoAssetPathResolver geoAssetPathResolver;
|
||||
// final DioHttpClient httpClient;
|
||||
|
||||
@override
|
||||
TaskEither<GeoAssetFailure, Unit> init() {
|
||||
return exceptionHandler(
|
||||
() async {
|
||||
loggy.debug("initializing");
|
||||
final geoipFile = geoAssetPathResolver.file(
|
||||
defaultGeoip.providerName,
|
||||
defaultGeoip.fileName,
|
||||
);
|
||||
final geositeFile = geoAssetPathResolver.file(
|
||||
defaultGeosite.providerName,
|
||||
defaultGeosite.fileName,
|
||||
);
|
||||
// @override
|
||||
// TaskEither<GeoAssetFailure, Unit> init() {
|
||||
// return exceptionHandler(
|
||||
// () async {
|
||||
// loggy.debug("initializing");
|
||||
// final geoipFile = geoAssetPathResolver.file(
|
||||
// defaultGeoip.providerName,
|
||||
// defaultGeoip.fileName,
|
||||
// );
|
||||
// final geositeFile = geoAssetPathResolver.file(
|
||||
// defaultGeosite.providerName,
|
||||
// defaultGeosite.fileName,
|
||||
// );
|
||||
|
||||
final dirExists = await geoAssetPathResolver.directory.exists();
|
||||
if (!dirExists) {
|
||||
await geoAssetPathResolver.directory.create(recursive: true);
|
||||
}
|
||||
// final dirExists = await geoAssetPathResolver.directory.exists();
|
||||
// if (!dirExists) {
|
||||
// await geoAssetPathResolver.directory.create(recursive: true);
|
||||
// }
|
||||
|
||||
if (!dirExists || !await geoipFile.exists()) {
|
||||
final bundledGeoip = await rootBundle.load(Assets.core.geoip);
|
||||
await geoipFile.writeAsBytes(bundledGeoip.buffer.asInt8List());
|
||||
}
|
||||
if (!dirExists || !await geositeFile.exists()) {
|
||||
final bundledGeosite = await rootBundle.load(Assets.core.geosite);
|
||||
await geositeFile.writeAsBytes(bundledGeosite.buffer.asInt8List());
|
||||
}
|
||||
return right(unit);
|
||||
},
|
||||
GeoAssetUnexpectedFailure.new,
|
||||
);
|
||||
}
|
||||
// if (!dirExists || !await geoipFile.exists()) {
|
||||
// final bundledGeoip = await rootBundle.load(Assets.core.geoip);
|
||||
// await geoipFile.writeAsBytes(bundledGeoip.buffer.asInt8List());
|
||||
// }
|
||||
// if (!dirExists || !await geositeFile.exists()) {
|
||||
// final bundledGeosite = await rootBundle.load(Assets.core.geosite);
|
||||
// await geositeFile.writeAsBytes(bundledGeosite.buffer.asInt8List());
|
||||
// }
|
||||
// return right(unit);
|
||||
// },
|
||||
// GeoAssetUnexpectedFailure.new,
|
||||
// );
|
||||
// }
|
||||
|
||||
@override
|
||||
TaskEither<GeoAssetFailure, ({GeoAssetEntity geoip, GeoAssetEntity geosite})>
|
||||
getActivePair() {
|
||||
return exceptionHandler(
|
||||
() async {
|
||||
final geoip =
|
||||
await geoAssetDataSource.getActiveAssetByType(GeoAssetType.geoip);
|
||||
final geosite =
|
||||
await geoAssetDataSource.getActiveAssetByType(GeoAssetType.geosite);
|
||||
if (geoip == null || geosite == null) {
|
||||
return left(const GeoAssetFailure.activeAssetNotFound());
|
||||
}
|
||||
return right((geoip: geoip.toEntity(), geosite: geosite.toEntity()));
|
||||
},
|
||||
GeoAssetUnexpectedFailure.new,
|
||||
);
|
||||
}
|
||||
// @override
|
||||
// TaskEither<GeoAssetFailure, ({GeoAssetEntity geoip, GeoAssetEntity geosite})>
|
||||
// getActivePair() {
|
||||
// return exceptionHandler(
|
||||
// () async {
|
||||
// final geoip =
|
||||
// await geoAssetDataSource.getActiveAssetByType(GeoAssetType.geoip);
|
||||
// final geosite =
|
||||
// await geoAssetDataSource.getActiveAssetByType(GeoAssetType.geosite);
|
||||
// if (geoip == null || geosite == null) {
|
||||
// return left(const GeoAssetFailure.activeAssetNotFound());
|
||||
// }
|
||||
// return right((geoip: geoip.toEntity(), geosite: geosite.toEntity()));
|
||||
// },
|
||||
// GeoAssetUnexpectedFailure.new,
|
||||
// );
|
||||
// }
|
||||
|
||||
@override
|
||||
Stream<Either<GeoAssetFailure, List<GeoAssetWithFileSize>>> watchAll() {
|
||||
final persistedStream = geoAssetDataSource
|
||||
.watchAll()
|
||||
.map((event) => event.map((e) => e.toEntity()));
|
||||
final filesStream = _watchGeoFiles();
|
||||
// @override
|
||||
// Stream<Either<GeoAssetFailure, List<GeoAssetWithFileSize>>> watchAll() {
|
||||
// final persistedStream = geoAssetDataSource
|
||||
// .watchAll()
|
||||
// .map((event) => event.map((e) => e.toEntity()));
|
||||
// final filesStream = _watchGeoFiles();
|
||||
|
||||
return Rx.combineLatest2(
|
||||
persistedStream,
|
||||
filesStream,
|
||||
(assets, files) => assets.map(
|
||||
(e) {
|
||||
final path =
|
||||
geoAssetPathResolver.file(e.providerName, e.fileName).path;
|
||||
final file = files.firstOrNullWhere((e) => e.path == path);
|
||||
final stat = file?.statSync();
|
||||
return (e, stat?.size);
|
||||
},
|
||||
).toList(),
|
||||
).handleExceptions(GeoAssetUnexpectedFailure.new);
|
||||
}
|
||||
// return Rx.combineLatest2(
|
||||
// persistedStream,
|
||||
// filesStream,
|
||||
// (assets, files) => assets.map(
|
||||
// (e) {
|
||||
// final path =
|
||||
// geoAssetPathResolver.file(e.providerName, e.fileName).path;
|
||||
// final file = files.firstOrNullWhere((e) => e.path == path);
|
||||
// final stat = file?.statSync();
|
||||
// return (e, stat?.size);
|
||||
// },
|
||||
// ).toList(),
|
||||
// ).handleExceptions(GeoAssetUnexpectedFailure.new);
|
||||
// }
|
||||
|
||||
Iterable<File> _geoFiles = [];
|
||||
Stream<Iterable<File>> _watchGeoFiles() async* {
|
||||
yield await _readGeoFiles();
|
||||
yield* Watcher(
|
||||
geoAssetPathResolver.directory.path,
|
||||
pollingDelay: const Duration(seconds: 1),
|
||||
).events.asyncMap((event) async {
|
||||
await _readGeoFiles();
|
||||
return _geoFiles;
|
||||
});
|
||||
}
|
||||
// Iterable<File> _geoFiles = [];
|
||||
// Stream<Iterable<File>> _watchGeoFiles() async* {
|
||||
// yield await _readGeoFiles();
|
||||
// yield* Watcher(
|
||||
// geoAssetPathResolver.directory.path,
|
||||
// pollingDelay: const Duration(seconds: 1),
|
||||
// ).events.asyncMap((event) async {
|
||||
// await _readGeoFiles();
|
||||
// return _geoFiles;
|
||||
// });
|
||||
// }
|
||||
|
||||
Future<Iterable<File>> _readGeoFiles() async {
|
||||
return _geoFiles = Directory(geoAssetPathResolver.directory.path)
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((e) => e.extension == '.db');
|
||||
}
|
||||
// Future<Iterable<File>> _readGeoFiles() async {
|
||||
// return _geoFiles = Directory(geoAssetPathResolver.directory.path)
|
||||
// .listSync()
|
||||
// .whereType<File>()
|
||||
// .where((e) => e.extension == '.db');
|
||||
// }
|
||||
|
||||
@override
|
||||
TaskEither<GeoAssetFailure, Unit> update(GeoAssetEntity geoAsset) {
|
||||
return exceptionHandler(
|
||||
() async {
|
||||
loggy.debug(
|
||||
"checking latest release of [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
|
||||
);
|
||||
final response = await httpClient.get<Map>(geoAsset.repositoryUrl);
|
||||
if (response.statusCode != 200 || response.data == null) {
|
||||
return left(
|
||||
GeoAssetUnexpectedFailure.new(
|
||||
"invalid response",
|
||||
StackTrace.current,
|
||||
),
|
||||
);
|
||||
}
|
||||
// @override
|
||||
// TaskEither<GeoAssetFailure, Unit> update(GeoAssetEntity geoAsset) {
|
||||
// return exceptionHandler(
|
||||
// () async {
|
||||
// loggy.debug(
|
||||
// "checking latest release of [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
|
||||
// );
|
||||
// final response = await httpClient.get<Map>(geoAsset.repositoryUrl);
|
||||
// if (response.statusCode != 200 || response.data == null) {
|
||||
// return left(
|
||||
// GeoAssetUnexpectedFailure.new(
|
||||
// "invalid response",
|
||||
// StackTrace.current,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
final file =
|
||||
geoAssetPathResolver.file(geoAsset.providerName, geoAsset.name);
|
||||
final tagName = response.data!['tag_name'] as String;
|
||||
loggy.debug("latest release of [${geoAsset.name}]: [$tagName]");
|
||||
if (tagName == geoAsset.version && await file.exists()) {
|
||||
await geoAssetDataSource.patch(
|
||||
geoAsset.id,
|
||||
GeoAssetEntriesCompanion(lastCheck: Value(DateTime.now())),
|
||||
);
|
||||
return left(const GeoAssetFailure.noUpdateAvailable());
|
||||
}
|
||||
// final file =
|
||||
// geoAssetPathResolver.file(geoAsset.providerName, geoAsset.name);
|
||||
// final tagName = response.data!['tag_name'] as String;
|
||||
// loggy.debug("latest release of [${geoAsset.name}]: [$tagName]");
|
||||
// if (tagName == geoAsset.version && await file.exists()) {
|
||||
// await geoAssetDataSource.patch(
|
||||
// geoAsset.id,
|
||||
// GeoAssetEntriesCompanion(lastCheck: Value(DateTime.now())),
|
||||
// );
|
||||
// return left(const GeoAssetFailure.noUpdateAvailable());
|
||||
// }
|
||||
|
||||
final assets = (response.data!['assets'] as List)
|
||||
.whereType<Map<String, dynamic>>();
|
||||
final asset =
|
||||
assets.firstOrNullWhere((e) => e["name"] == geoAsset.name);
|
||||
if (asset == null) {
|
||||
return left(
|
||||
GeoAssetUnexpectedFailure.new(
|
||||
"couldn't find [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
|
||||
StackTrace.current,
|
||||
),
|
||||
);
|
||||
}
|
||||
// final assets = (response.data!['assets'] as List)
|
||||
// .whereType<Map<String, dynamic>>();
|
||||
// final asset =
|
||||
// assets.firstOrNullWhere((e) => e["name"] == geoAsset.name);
|
||||
// if (asset == null) {
|
||||
// return left(
|
||||
// GeoAssetUnexpectedFailure.new(
|
||||
// "couldn't find [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
|
||||
// StackTrace.current,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
final downloadUrl = asset["browser_download_url"] as String;
|
||||
loggy.debug("[${geoAsset.name}] download url: [$downloadUrl]");
|
||||
final tempPath = "${file.path}.tmp";
|
||||
await file.parent.create(recursive: true);
|
||||
await httpClient.download(downloadUrl, tempPath);
|
||||
await File(tempPath).rename(file.path);
|
||||
// final downloadUrl = asset["browser_download_url"] as String;
|
||||
// loggy.debug("[${geoAsset.name}] download url: [$downloadUrl]");
|
||||
// final tempPath = "${file.path}.tmp";
|
||||
// await file.parent.create(recursive: true);
|
||||
// await httpClient.download(downloadUrl, tempPath);
|
||||
// await File(tempPath).rename(file.path);
|
||||
|
||||
await geoAssetDataSource.patch(
|
||||
geoAsset.id,
|
||||
GeoAssetEntriesCompanion(
|
||||
version: Value(tagName),
|
||||
lastCheck: Value(DateTime.now()),
|
||||
),
|
||||
);
|
||||
// await geoAssetDataSource.patch(
|
||||
// geoAsset.id,
|
||||
// GeoAssetEntriesCompanion(
|
||||
// version: Value(tagName),
|
||||
// lastCheck: Value(DateTime.now()),
|
||||
// ),
|
||||
// );
|
||||
|
||||
return right(unit);
|
||||
},
|
||||
GeoAssetUnexpectedFailure.new,
|
||||
);
|
||||
}
|
||||
// return right(unit);
|
||||
// },
|
||||
// GeoAssetUnexpectedFailure.new,
|
||||
// );
|
||||
// }
|
||||
|
||||
@override
|
||||
TaskEither<GeoAssetFailure, Unit> markAsActive(GeoAssetEntity geoAsset) {
|
||||
return exceptionHandler(
|
||||
() async {
|
||||
await geoAssetDataSource.patch(
|
||||
geoAsset.id,
|
||||
const GeoAssetEntriesCompanion(active: Value(true)),
|
||||
);
|
||||
return right(unit);
|
||||
},
|
||||
GeoAssetUnexpectedFailure.new,
|
||||
);
|
||||
}
|
||||
// @override
|
||||
// TaskEither<GeoAssetFailure, Unit> markAsActive(GeoAssetEntity geoAsset) {
|
||||
// return exceptionHandler(
|
||||
// () async {
|
||||
// await geoAssetDataSource.patch(
|
||||
// geoAsset.id,
|
||||
// const GeoAssetEntriesCompanion(active: Value(true)),
|
||||
// );
|
||||
// return right(unit);
|
||||
// },
|
||||
// GeoAssetUnexpectedFailure.new,
|
||||
// );
|
||||
// }
|
||||
|
||||
@override
|
||||
TaskEither<GeoAssetFailure, Unit> addRecommended() {
|
||||
return exceptionHandler(
|
||||
() async {
|
||||
final persistedIds = await geoAssetDataSource
|
||||
.watchAll()
|
||||
.first
|
||||
.then((value) => value.map((e) => e.id));
|
||||
final missing =
|
||||
recommendedGeoAssets.where((e) => !persistedIds.contains(e.id));
|
||||
for (final geoAsset in missing) {
|
||||
await geoAssetDataSource.insert(geoAsset.toEntry());
|
||||
}
|
||||
return right(unit);
|
||||
},
|
||||
GeoAssetUnexpectedFailure.new,
|
||||
);
|
||||
}
|
||||
}
|
||||
// @override
|
||||
// TaskEither<GeoAssetFailure, Unit> addRecommended() {
|
||||
// return exceptionHandler(
|
||||
// () async {
|
||||
// final persistedIds = await geoAssetDataSource
|
||||
// .watchAll()
|
||||
// .first
|
||||
// .then((value) => value.map((e) => e.id));
|
||||
// final missing =
|
||||
// recommendedGeoAssets.where((e) => !persistedIds.contains(e.id));
|
||||
// for (final geoAsset in missing) {
|
||||
// await geoAssetDataSource.insert(geoAsset.toEntry());
|
||||
// }
|
||||
// return right(unit);
|
||||
// },
|
||||
// GeoAssetUnexpectedFailure.new,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
|
||||
/// default geoip asset bundled with the app
|
||||
const defaultGeoip = GeoAssetEntity(
|
||||
id: "sing-box-geoip",
|
||||
name: "geoip.db",
|
||||
type: GeoAssetType.geoip,
|
||||
active: true,
|
||||
providerName: "SagerNet/sing-geoip",
|
||||
);
|
||||
// /// default geoip asset bundled with the app
|
||||
// const defaultGeoip = GeoAssetEntity(
|
||||
// id: "sing-box-geoip",
|
||||
// name: "geoip.db",
|
||||
// type: GeoAssetType.geoip,
|
||||
// active: true,
|
||||
// providerName: "SagerNet/sing-geoip",
|
||||
// );
|
||||
|
||||
/// default geosite asset bundled with the app
|
||||
const defaultGeosite = GeoAssetEntity(
|
||||
id: "sing-box-geosite",
|
||||
name: "geosite.db",
|
||||
type: GeoAssetType.geosite,
|
||||
active: true,
|
||||
providerName: "SagerNet/sing-geosite",
|
||||
);
|
||||
// /// default geosite asset bundled with the app
|
||||
// const defaultGeosite = GeoAssetEntity(
|
||||
// id: "sing-box-geosite",
|
||||
// name: "geosite.db",
|
||||
// type: GeoAssetType.geosite,
|
||||
// active: true,
|
||||
// providerName: "SagerNet/sing-geosite",
|
||||
// );
|
||||
|
||||
const defaultGeoAssets = [defaultGeoip, defaultGeosite];
|
||||
// const defaultGeoAssets = [defaultGeoip, defaultGeosite];
|
||||
|
||||
const recommendedGeoAssets = [
|
||||
...defaultGeoAssets,
|
||||
GeoAssetEntity(
|
||||
id: "chocolate4U-geoip",
|
||||
name: "geoip.db",
|
||||
type: GeoAssetType.geoip,
|
||||
active: false,
|
||||
providerName: "Chocolate4U/Iran-sing-box-rules",
|
||||
),
|
||||
GeoAssetEntity(
|
||||
id: "chocolate4U-geosite",
|
||||
name: "geosite.db",
|
||||
type: GeoAssetType.geosite,
|
||||
active: false,
|
||||
providerName: "Chocolate4U/Iran-sing-box-rules",
|
||||
),
|
||||
GeoAssetEntity(
|
||||
id: "soffchen-geoip",
|
||||
name: "geoip.db",
|
||||
type: GeoAssetType.geoip,
|
||||
active: false,
|
||||
providerName: "soffchen/sing-geoip",
|
||||
),
|
||||
GeoAssetEntity(
|
||||
id: "soffchen-geosite",
|
||||
name: "geosite.db",
|
||||
type: GeoAssetType.geosite,
|
||||
active: false,
|
||||
providerName: "soffchen/sing-geosite",
|
||||
),
|
||||
];
|
||||
// const recommendedGeoAssets = [
|
||||
// ...defaultGeoAssets,
|
||||
// GeoAssetEntity(
|
||||
// id: "chocolate4U-geoip",
|
||||
// name: "geoip.db",
|
||||
// type: GeoAssetType.geoip,
|
||||
// active: false,
|
||||
// providerName: "Chocolate4U/Iran-sing-box-rules",
|
||||
// ),
|
||||
// GeoAssetEntity(
|
||||
// id: "chocolate4U-geosite",
|
||||
// name: "geosite.db",
|
||||
// type: GeoAssetType.geosite,
|
||||
// active: false,
|
||||
// providerName: "Chocolate4U/Iran-sing-box-rules",
|
||||
// ),
|
||||
// GeoAssetEntity(
|
||||
// id: "soffchen-geoip",
|
||||
// name: "geoip.db",
|
||||
// type: GeoAssetType.geoip,
|
||||
// active: false,
|
||||
// providerName: "soffchen/sing-geoip",
|
||||
// ),
|
||||
// GeoAssetEntity(
|
||||
// id: "soffchen-geosite",
|
||||
// name: "geosite.db",
|
||||
// type: GeoAssetType.geosite,
|
||||
// active: false,
|
||||
// providerName: "soffchen/sing-geosite",
|
||||
// ),
|
||||
// ];
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
import 'package:hiddify/utils/custom_loggers.dart';
|
||||
import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
// import 'package:fpdart/fpdart.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
// import 'package:hiddify/utils/custom_loggers.dart';
|
||||
// import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
// import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'geo_asset_notifier.g.dart';
|
||||
// part 'geo_asset_notifier.g.dart';
|
||||
|
||||
@riverpod
|
||||
class FetchGeoAsset extends _$FetchGeoAsset with AppLogger {
|
||||
@override
|
||||
Future<Unit?> build(String id) async {
|
||||
ref.disposeDelay(const Duration(seconds: 10));
|
||||
return null;
|
||||
}
|
||||
// @riverpod
|
||||
// class FetchGeoAsset extends _$FetchGeoAsset with AppLogger {
|
||||
// @override
|
||||
// Future<Unit?> build(String id) async {
|
||||
// ref.disposeDelay(const Duration(seconds: 10));
|
||||
// return null;
|
||||
// }
|
||||
|
||||
Future<void> fetch(GeoAssetEntity geoAsset) async {
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(
|
||||
() => ref
|
||||
.read(geoAssetRepositoryProvider)
|
||||
.requireValue
|
||||
.update(geoAsset)
|
||||
.getOrElse(
|
||||
(failure) {
|
||||
loggy.warning("error updating geo asset $failure", failure);
|
||||
throw failure;
|
||||
},
|
||||
).run(),
|
||||
);
|
||||
}
|
||||
}
|
||||
// Future<void> fetch(GeoAssetEntity geoAsset) async {
|
||||
// state = const AsyncLoading();
|
||||
// state = await AsyncValue.guard(
|
||||
// () => ref
|
||||
// .read(geoAssetRepositoryProvider)
|
||||
// .requireValue
|
||||
// .update(geoAsset)
|
||||
// .getOrElse(
|
||||
// (failure) {
|
||||
// loggy.warning("error updating geo asset $failure", failure);
|
||||
// throw failure;
|
||||
// },
|
||||
// ).run(),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
import 'package:dartx/dartx.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_repository.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
import 'package:hiddify/utils/custom_loggers.dart';
|
||||
import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
// import 'package:dartx/dartx.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
// import 'package:hiddify/features/geo_asset/data/geo_asset_repository.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
// import 'package:hiddify/utils/custom_loggers.dart';
|
||||
// import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
// import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'geo_assets_overview_notifier.g.dart';
|
||||
// part 'geo_assets_overview_notifier.g.dart';
|
||||
|
||||
typedef GroupedRoutingAssets = ({
|
||||
List<GeoAssetWithFileSize> geoip,
|
||||
List<GeoAssetWithFileSize> geosite,
|
||||
});
|
||||
// typedef GroupedRoutingAssets = ({
|
||||
// List<GeoAssetWithFileSize> geoip,
|
||||
// List<GeoAssetWithFileSize> geosite,
|
||||
// });
|
||||
|
||||
@riverpod
|
||||
class GeoAssetsOverviewNotifier extends _$GeoAssetsOverviewNotifier
|
||||
with AppLogger {
|
||||
@override
|
||||
Stream<GroupedRoutingAssets> build() {
|
||||
ref.disposeDelay(const Duration(seconds: 5));
|
||||
return ref.watch(geoAssetRepositoryProvider).requireValue.watchAll().map(
|
||||
(event) {
|
||||
final grouped = event
|
||||
.getOrElse((l) => throw l)
|
||||
.groupBy((element) => element.$1.type);
|
||||
return (
|
||||
geoip: grouped.getOrElse(GeoAssetType.geoip, () => []),
|
||||
geosite: grouped.getOrElse(GeoAssetType.geosite, () => []),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
// @riverpod
|
||||
// class GeoAssetsOverviewNotifier extends _$GeoAssetsOverviewNotifier
|
||||
// with AppLogger {
|
||||
// @override
|
||||
// Stream<GroupedRoutingAssets> build() {
|
||||
// ref.disposeDelay(const Duration(seconds: 5));
|
||||
// return ref.watch(geoAssetRepositoryProvider).requireValue.watchAll().map(
|
||||
// (event) {
|
||||
// final grouped = event
|
||||
// .getOrElse((l) => throw l)
|
||||
// .groupBy((element) => element.$1.type);
|
||||
// return (
|
||||
// geoip: grouped.getOrElse(GeoAssetType.geoip, () => []),
|
||||
// geosite: grouped.getOrElse(GeoAssetType.geosite, () => []),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
GeoAssetRepository get _geoAssetRepo =>
|
||||
ref.read(geoAssetRepositoryProvider).requireValue;
|
||||
// GeoAssetRepository get _geoAssetRepo =>
|
||||
// ref.read(geoAssetRepositoryProvider).requireValue;
|
||||
|
||||
Future<void> markAsActive(GeoAssetEntity geoAsset) async {
|
||||
await _geoAssetRepo.markAsActive(geoAsset).getOrElse(
|
||||
(f) {
|
||||
loggy.warning("error marking geo asset as active", f);
|
||||
throw f;
|
||||
},
|
||||
).run();
|
||||
}
|
||||
// Future<void> markAsActive(GeoAssetEntity geoAsset) async {
|
||||
// await _geoAssetRepo.markAsActive(geoAsset).getOrElse(
|
||||
// (f) {
|
||||
// loggy.warning("error marking geo asset as active", f);
|
||||
// throw f;
|
||||
// },
|
||||
// ).run();
|
||||
// }
|
||||
|
||||
Future<void> addRecommended() async {
|
||||
await _geoAssetRepo.addRecommended().getOrElse(
|
||||
(f) {
|
||||
loggy.warning("error adding recommended geo assets", f);
|
||||
throw f;
|
||||
},
|
||||
).run();
|
||||
}
|
||||
}
|
||||
// Future<void> addRecommended() async {
|
||||
// await _geoAssetRepo.addRecommended().getOrElse(
|
||||
// (f) {
|
||||
// loggy.warning("error adding recommended geo assets", f);
|
||||
// throw f;
|
||||
// },
|
||||
// ).run();
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,102 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/core/widget/adaptive_icon.dart';
|
||||
import 'package:hiddify/core/widget/animated_visibility.dart';
|
||||
import 'package:hiddify/core/widget/tip_card.dart';
|
||||
import 'package:hiddify/features/geo_asset/overview/geo_assets_overview_notifier.dart';
|
||||
import 'package:hiddify/features/geo_asset/widget/geo_asset_tile.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:sliver_tools/sliver_tools.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:gap/gap.dart';
|
||||
// import 'package:hiddify/core/localization/translations.dart';
|
||||
// import 'package:hiddify/core/widget/adaptive_icon.dart';
|
||||
// import 'package:hiddify/core/widget/animated_visibility.dart';
|
||||
// import 'package:hiddify/core/widget/tip_card.dart';
|
||||
// import 'package:hiddify/features/geo_asset/overview/geo_assets_overview_notifier.dart';
|
||||
// import 'package:hiddify/features/geo_asset/widget/geo_asset_tile.dart';
|
||||
// import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
// import 'package:sliver_tools/sliver_tools.dart';
|
||||
|
||||
class GeoAssetsOverviewPage extends HookConsumerWidget {
|
||||
const GeoAssetsOverviewPage({super.key});
|
||||
// class GeoAssetsOverviewPage extends HookConsumerWidget {
|
||||
// const GeoAssetsOverviewPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final t = ref.watch(translationsProvider);
|
||||
final state = ref.watch(geoAssetsOverviewNotifierProvider);
|
||||
// @override
|
||||
// Widget build(BuildContext context, WidgetRef ref) {
|
||||
// final t = ref.watch(translationsProvider);
|
||||
// final state = ref.watch(geoAssetsOverviewNotifierProvider);
|
||||
|
||||
return Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
title: Text(t.settings.geoAssets.pageTitle),
|
||||
pinned: true,
|
||||
actions: [
|
||||
PopupMenuButton(
|
||||
icon: Icon(AdaptiveIcon(context).more),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: Text(t.settings.geoAssets.addRecommended),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
.addRecommended();
|
||||
},
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
if (state case AsyncData(value: (:final geoip, :final geosite)))
|
||||
SliverPinnedHeader(
|
||||
child: AnimatedVisibility(
|
||||
visible: (geoip + geosite)
|
||||
.where((e) => e.$1.active && e.$2 == null)
|
||||
.isNotEmpty,
|
||||
axis: Axis.vertical,
|
||||
child:
|
||||
TipCard(message: t.settings.geoAssets.missingGeoAssetsMsg),
|
||||
),
|
||||
),
|
||||
switch (state) {
|
||||
AsyncData(value: (:final geoip, :final geosite)) => MultiSliver(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text("${t.settings.geoAssets.geoip} ›"),
|
||||
titleTextStyle: Theme.of(context).textTheme.headlineSmall,
|
||||
dense: true,
|
||||
),
|
||||
SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final geoAsset = geoip[index];
|
||||
return GeoAssetTile(
|
||||
geoAsset,
|
||||
onMarkAsActive: () => ref
|
||||
.read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
.markAsActive(geoAsset.$1),
|
||||
);
|
||||
},
|
||||
itemCount: geoip.length,
|
||||
),
|
||||
const Divider(indent: 16, endIndent: 16),
|
||||
ListTile(
|
||||
title: Text("${t.settings.geoAssets.geosite} ›"),
|
||||
titleTextStyle: Theme.of(context).textTheme.headlineSmall,
|
||||
dense: true,
|
||||
),
|
||||
SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final geoAsset = geosite[index];
|
||||
return GeoAssetTile(
|
||||
geoAsset,
|
||||
onMarkAsActive: () => ref
|
||||
.read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
.markAsActive(geoAsset.$1),
|
||||
);
|
||||
},
|
||||
itemCount: geosite.length,
|
||||
),
|
||||
const Gap(16),
|
||||
],
|
||||
),
|
||||
_ => const SliverToBoxAdapter(),
|
||||
},
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// return Scaffold(
|
||||
// body: CustomScrollView(
|
||||
// slivers: [
|
||||
// SliverAppBar(
|
||||
// title: Text(t.settings.geoAssets.pageTitle),
|
||||
// pinned: true,
|
||||
// actions: [
|
||||
// PopupMenuButton(
|
||||
// icon: Icon(AdaptiveIcon(context).more),
|
||||
// itemBuilder: (context) {
|
||||
// return [
|
||||
// PopupMenuItem(
|
||||
// child: Text(t.settings.geoAssets.addRecommended),
|
||||
// onTap: () {
|
||||
// ref
|
||||
// .read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
// .addRecommended();
|
||||
// },
|
||||
// ),
|
||||
// ];
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// if (state case AsyncData(value: (:final geoip, :final geosite)))
|
||||
// SliverPinnedHeader(
|
||||
// child: AnimatedVisibility(
|
||||
// visible: (geoip + geosite)
|
||||
// .where((e) => e.$1.active && e.$2 == null)
|
||||
// .isNotEmpty,
|
||||
// axis: Axis.vertical,
|
||||
// child:
|
||||
// TipCard(message: t.settings.geoAssets.missingGeoAssetsMsg),
|
||||
// ),
|
||||
// ),
|
||||
// switch (state) {
|
||||
// AsyncData(value: (:final geoip, :final geosite)) => MultiSliver(
|
||||
// children: [
|
||||
// ListTile(
|
||||
// title: Text("${t.settings.geoAssets.geoip} ›"),
|
||||
// titleTextStyle: Theme.of(context).textTheme.headlineSmall,
|
||||
// dense: true,
|
||||
// ),
|
||||
// SliverList.builder(
|
||||
// itemBuilder: (context, index) {
|
||||
// final geoAsset = geoip[index];
|
||||
// return GeoAssetTile(
|
||||
// geoAsset,
|
||||
// onMarkAsActive: () => ref
|
||||
// .read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
// .markAsActive(geoAsset.$1),
|
||||
// );
|
||||
// },
|
||||
// itemCount: geoip.length,
|
||||
// ),
|
||||
// const Divider(indent: 16, endIndent: 16),
|
||||
// ListTile(
|
||||
// title: Text("${t.settings.geoAssets.geosite} ›"),
|
||||
// titleTextStyle: Theme.of(context).textTheme.headlineSmall,
|
||||
// dense: true,
|
||||
// ),
|
||||
// SliverList.builder(
|
||||
// itemBuilder: (context, index) {
|
||||
// final geoAsset = geosite[index];
|
||||
// return GeoAssetTile(
|
||||
// geoAsset,
|
||||
// onMarkAsActive: () => ref
|
||||
// .read(geoAssetsOverviewNotifierProvider.notifier)
|
||||
// .markAsActive(geoAsset.$1),
|
||||
// );
|
||||
// },
|
||||
// itemCount: geosite.length,
|
||||
// ),
|
||||
// const Gap(16),
|
||||
// ],
|
||||
// ),
|
||||
// _ => const SliverToBoxAdapter(),
|
||||
// },
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,116 +1,116 @@
|
||||
import 'package:dartx/dartx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/core/model/failures.dart';
|
||||
import 'package:hiddify/core/widget/adaptive_icon.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
import 'package:hiddify/features/geo_asset/model/geo_asset_failure.dart';
|
||||
import 'package:hiddify/features/geo_asset/notifier/geo_asset_notifier.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:humanizer/humanizer.dart';
|
||||
// import 'package:dartx/dartx.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:hiddify/core/localization/translations.dart';
|
||||
// import 'package:hiddify/core/model/failures.dart';
|
||||
// import 'package:hiddify/core/widget/adaptive_icon.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_entity.dart';
|
||||
// import 'package:hiddify/features/geo_asset/model/geo_asset_failure.dart';
|
||||
// import 'package:hiddify/features/geo_asset/notifier/geo_asset_notifier.dart';
|
||||
// import 'package:hiddify/utils/utils.dart';
|
||||
// import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
// import 'package:humanizer/humanizer.dart';
|
||||
|
||||
class GeoAssetTile extends HookConsumerWidget {
|
||||
GeoAssetTile(
|
||||
GeoAssetWithFileSize geoAssetWithFileSize, {
|
||||
super.key,
|
||||
required this.onMarkAsActive,
|
||||
}) : geoAsset = geoAssetWithFileSize.$1,
|
||||
size = geoAssetWithFileSize.$2;
|
||||
// class GeoAssetTile extends HookConsumerWidget {
|
||||
// GeoAssetTile(
|
||||
// GeoAssetWithFileSize geoAssetWithFileSize, {
|
||||
// super.key,
|
||||
// required this.onMarkAsActive,
|
||||
// }) : geoAsset = geoAssetWithFileSize.$1,
|
||||
// size = geoAssetWithFileSize.$2;
|
||||
|
||||
final GeoAssetEntity geoAsset;
|
||||
final int? size;
|
||||
final VoidCallback onMarkAsActive;
|
||||
// final GeoAssetEntity geoAsset;
|
||||
// final int? size;
|
||||
// final VoidCallback onMarkAsActive;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final t = ref.watch(translationsProvider);
|
||||
final fetchState = ref.watch(fetchGeoAssetProvider(geoAsset.id));
|
||||
final fileMissing = size == null;
|
||||
// @override
|
||||
// Widget build(BuildContext context, WidgetRef ref) {
|
||||
// final t = ref.watch(translationsProvider);
|
||||
// final fetchState = ref.watch(fetchGeoAssetProvider(geoAsset.id));
|
||||
// final fileMissing = size == null;
|
||||
|
||||
ref.listen(
|
||||
fetchGeoAssetProvider(geoAsset.id),
|
||||
(_, next) {
|
||||
switch (next) {
|
||||
case AsyncError(:final error):
|
||||
if (error case GeoAssetNoUpdateAvailable()) {
|
||||
return CustomToast(t.failure.geoAssets.notUpdate).show(context);
|
||||
}
|
||||
CustomAlertDialog.fromErr(t.presentError(error)).show(context);
|
||||
case AsyncData(value: final _?):
|
||||
CustomToast.success(t.settings.geoAssets.successMsg).show(context);
|
||||
}
|
||||
},
|
||||
);
|
||||
// ref.listen(
|
||||
// fetchGeoAssetProvider(geoAsset.id),
|
||||
// (_, next) {
|
||||
// switch (next) {
|
||||
// case AsyncError(:final error):
|
||||
// if (error case GeoAssetNoUpdateAvailable()) {
|
||||
// return CustomToast(t.failure.geoAssets.notUpdate).show(context);
|
||||
// }
|
||||
// CustomAlertDialog.fromErr(t.presentError(error)).show(context);
|
||||
// case AsyncData(value: final _?):
|
||||
// CustomToast.success(t.settings.geoAssets.successMsg).show(context);
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
|
||||
return ListTile(
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: geoAsset.name),
|
||||
if (geoAsset.providerName.isNotBlank)
|
||||
TextSpan(text: " (${geoAsset.providerName})"),
|
||||
],
|
||||
),
|
||||
),
|
||||
isThreeLine: true,
|
||||
subtitle: fetchState.isLoading
|
||||
? const LinearProgressIndicator()
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (geoAsset.version.isNotNullOrBlank)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 8),
|
||||
child: Text(
|
||||
t.settings.geoAssets.version(version: geoAsset.version!),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
else
|
||||
const SizedBox(),
|
||||
Flexible(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
if (fileMissing)
|
||||
TextSpan(
|
||||
text: t.settings.geoAssets.fileMissing,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
)
|
||||
else
|
||||
TextSpan(text: size?.bytes().toString()),
|
||||
if (geoAsset.lastCheck != null) ...[
|
||||
const TextSpan(text: " • "),
|
||||
TextSpan(text: geoAsset.lastCheck!.format()),
|
||||
],
|
||||
],
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
selected: geoAsset.active,
|
||||
onTap: onMarkAsActive,
|
||||
trailing: PopupMenuButton(
|
||||
icon: Icon(AdaptiveIcon(context).more),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
enabled: !fetchState.isLoading,
|
||||
onTap: () => ref
|
||||
.read(FetchGeoAssetProvider(geoAsset.id).notifier)
|
||||
.fetch(geoAsset),
|
||||
child: fileMissing
|
||||
? Text(t.settings.geoAssets.download)
|
||||
: Text(t.settings.geoAssets.update),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// return ListTile(
|
||||
// title: Text.rich(
|
||||
// TextSpan(
|
||||
// children: [
|
||||
// TextSpan(text: geoAsset.name),
|
||||
// if (geoAsset.providerName.isNotBlank)
|
||||
// TextSpan(text: " (${geoAsset.providerName})"),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// isThreeLine: true,
|
||||
// subtitle: fetchState.isLoading
|
||||
// ? const LinearProgressIndicator()
|
||||
// : Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// if (geoAsset.version.isNotNullOrBlank)
|
||||
// Padding(
|
||||
// padding: const EdgeInsetsDirectional.only(end: 8),
|
||||
// child: Text(
|
||||
// t.settings.geoAssets.version(version: geoAsset.version!),
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// )
|
||||
// else
|
||||
// const SizedBox(),
|
||||
// Flexible(
|
||||
// child: Text.rich(
|
||||
// TextSpan(
|
||||
// children: [
|
||||
// if (fileMissing)
|
||||
// TextSpan(
|
||||
// text: t.settings.geoAssets.fileMissing,
|
||||
// style: TextStyle(
|
||||
// color: Theme.of(context).colorScheme.error,
|
||||
// ),
|
||||
// )
|
||||
// else
|
||||
// TextSpan(text: size?.bytes().toString()),
|
||||
// if (geoAsset.lastCheck != null) ...[
|
||||
// const TextSpan(text: " • "),
|
||||
// TextSpan(text: geoAsset.lastCheck!.format()),
|
||||
// ],
|
||||
// ],
|
||||
// ),
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// selected: geoAsset.active,
|
||||
// onTap: onMarkAsActive,
|
||||
// trailing: PopupMenuButton(
|
||||
// icon: Icon(AdaptiveIcon(context).more),
|
||||
// itemBuilder: (context) {
|
||||
// return [
|
||||
// PopupMenuItem(
|
||||
// enabled: !fetchState.isLoading,
|
||||
// onTap: () => ref
|
||||
// .read(FetchGeoAssetProvider(geoAsset.id).notifier)
|
||||
// .fetch(geoAsset),
|
||||
// child: fileMissing
|
||||
// ? Text(t.settings.geoAssets.download)
|
||||
// : Text(t.settings.geoAssets.update),
|
||||
// ),
|
||||
// ];
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user