diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index c6ed7fc..f712d80 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -331,5 +331,8 @@ "add_torrent": "Add torrent", "enter_torrent_hint_text": "Enter magnet or torrent file url", "torrent_url": "Torrent url", - "or": "OR" + "or": "OR", + "advanced": "Advanced", + "use_native_http_client": "Use native http client", + "use_native_http_client_info": "it automatically supports platform features such VPNs, support more HTTP features such as HTTP/3 and custom redirect handling" } \ No newline at end of file diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 19e6cca..274711a 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -188,6 +188,8 @@ class Settings { bool? useLibass; + bool? useNativeHttpClient; + Settings( {this.id = 227, this.displayType = DisplayType.compactGrid, @@ -270,7 +272,8 @@ class Settings { this.mangaGridSize, this.animeGridSize, this.disableSectionType = SectionType.all, - this.useLibass = true}); + this.useLibass = true, + this.useNativeHttpClient = false}); Settings.fromJson(Map json) { animatePageTransitions = json['animatePageTransitions']; @@ -420,6 +423,7 @@ class Settings { disableSectionType = SectionType.values[json['disableSectionType'] ?? SectionType.all]; useLibass = json['useLibass']; + useNativeHttpClient = json['useNativeHttpClient']; } Map toJson() => { @@ -528,7 +532,8 @@ class Settings { 'mangaGridSize': mangaGridSize, 'animeGridSize': animeGridSize, 'disableSectionType': disableSectionType.index, - 'useLibass': useLibass + 'useLibass': useLibass, + 'useNativeHttpClient': useNativeHttpClient }; } diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index d1305e6..018a81b 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -456,13 +456,18 @@ const SettingsSchema = CollectionSchema( name: r'useLibass', type: IsarType.bool, ), - r'usePageTapZones': PropertySchema( + r'useNativeHttpClient': PropertySchema( id: 83, + name: r'useNativeHttpClient', + type: IsarType.bool, + ), + r'usePageTapZones': PropertySchema( + id: 84, name: r'usePageTapZones', type: IsarType.bool, ), r'userAgent': PropertySchema( - id: 84, + id: 85, name: r'userAgent', type: IsarType.string, ) @@ -917,8 +922,9 @@ void _settingsSerialize( writer.writeBool(offsets[80], object.themeIsDark); writer.writeBool(offsets[81], object.updateProgressAfterReading); writer.writeBool(offsets[82], object.useLibass); - writer.writeBool(offsets[83], object.usePageTapZones); - writer.writeString(offsets[84], object.userAgent); + writer.writeBool(offsets[83], object.useNativeHttpClient); + writer.writeBool(offsets[84], object.usePageTapZones); + writer.writeString(offsets[85], object.userAgent); } Settings _settingsDeserialize( @@ -1080,8 +1086,9 @@ Settings _settingsDeserialize( themeIsDark: reader.readBoolOrNull(offsets[80]), updateProgressAfterReading: reader.readBoolOrNull(offsets[81]), useLibass: reader.readBoolOrNull(offsets[82]), - usePageTapZones: reader.readBoolOrNull(offsets[83]), - userAgent: reader.readStringOrNull(offsets[84]), + useNativeHttpClient: reader.readBoolOrNull(offsets[83]), + usePageTapZones: reader.readBoolOrNull(offsets[84]), + userAgent: reader.readStringOrNull(offsets[85]), ); object.chapterFilterBookmarkedList = reader.readObjectList( @@ -1375,6 +1382,8 @@ P _settingsDeserializeProp

( case 83: return (reader.readBoolOrNull(offset)) as P; case 84: + return (reader.readBoolOrNull(offset)) as P; + case 85: return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -6840,6 +6849,34 @@ extension SettingsQueryFilter }); } + QueryBuilder + useNativeHttpClientIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'useNativeHttpClient', + )); + }); + } + + QueryBuilder + useNativeHttpClientIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'useNativeHttpClient', + )); + }); + } + + QueryBuilder + useNativeHttpClientEqualTo(bool? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'useNativeHttpClient', + value: value, + )); + }); + } + QueryBuilder usePageTapZonesIsNull() { return QueryBuilder.apply(this, (query) { @@ -8055,6 +8092,19 @@ extension SettingsQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByUseNativeHttpClient() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'useNativeHttpClient', Sort.asc); + }); + } + + QueryBuilder + sortByUseNativeHttpClientDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'useNativeHttpClient', Sort.desc); + }); + } + QueryBuilder sortByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'usePageTapZones', Sort.asc); @@ -8955,6 +9005,19 @@ extension SettingsQuerySortThenBy }); } + QueryBuilder thenByUseNativeHttpClient() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'useNativeHttpClient', Sort.asc); + }); + } + + QueryBuilder + thenByUseNativeHttpClientDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'useNativeHttpClient', Sort.desc); + }); + } + QueryBuilder thenByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'usePageTapZones', Sort.asc); @@ -9423,6 +9486,12 @@ extension SettingsQueryWhereDistinct }); } + QueryBuilder distinctByUseNativeHttpClient() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'useNativeHttpClient'); + }); + } + QueryBuilder distinctByUsePageTapZones() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'usePageTapZones'); @@ -9999,6 +10068,13 @@ extension SettingsQueryProperty }); } + QueryBuilder + useNativeHttpClientProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'useNativeHttpClient'); + }); + } + QueryBuilder usePageTapZonesProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'usePageTapZones'); diff --git a/lib/modules/more/more_screen.dart b/lib/modules/more/more_screen.dart index d3cf0d0..1b35bf5 100644 --- a/lib/modules/more/more_screen.dart +++ b/lib/modules/more/more_screen.dart @@ -63,7 +63,6 @@ class MoreScreen extends StatelessWidget { title: l10n.backup_and_restore, ), const Divider(), - ListTileWidget( onTap: () { context.push('/settings'); diff --git a/lib/modules/more/settings/advanced/advanced.dart b/lib/modules/more/settings/advanced/advanced.dart new file mode 100644 index 0000000..5d79ffe --- /dev/null +++ b/lib/modules/more/settings/advanced/advanced.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:mangayomi/modules/more/settings/advanced/providers/native_http_client.dart'; +import 'package:mangayomi/providers/l10n_providers.dart'; +import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; + +class AdvancedScreen extends ConsumerWidget { + const AdvancedScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final l10n = l10nLocalizations(context)!; + final useNativeHttpClient = ref.watch(useNativeHttpClientStateProvider); + + return Scaffold( + appBar: AppBar( + title: Text(l10n.advanced), + ), + body: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: SwitchListTile( + title: Text(l10n.use_native_http_client), + subtitle: Text( + l10n.use_native_http_client_info, + style: + TextStyle(fontSize: 11, color: context.secondaryColor), + ), + value: useNativeHttpClient, + onChanged: (value) { + ref + .read(useNativeHttpClientStateProvider.notifier) + .set(value); + }), + ), + ], + ), + ), + ); + } +} diff --git a/lib/modules/more/settings/advanced/providers/native_http_client.dart b/lib/modules/more/settings/advanced/providers/native_http_client.dart new file mode 100644 index 0000000..23c2209 --- /dev/null +++ b/lib/modules/more/settings/advanced/providers/native_http_client.dart @@ -0,0 +1,19 @@ +import 'package:mangayomi/main.dart'; +import 'package:mangayomi/models/settings.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +part 'native_http_client.g.dart'; + +@riverpod +class UseNativeHttpClientState extends _$UseNativeHttpClientState { + @override + bool build() { + return isar.settings.getSync(227)!.useNativeHttpClient ?? false; + } + + void set(bool value) { + final settings = isar.settings.getSync(227); + state = value; + isar.writeTxnSync( + () => isar.settings.putSync(settings!..useNativeHttpClient = value)); + } +} diff --git a/lib/modules/more/settings/advanced/providers/native_http_client.g.dart b/lib/modules/more/settings/advanced/providers/native_http_client.g.dart new file mode 100644 index 0000000..4fa0318 --- /dev/null +++ b/lib/modules/more/settings/advanced/providers/native_http_client.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'native_http_client.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$useNativeHttpClientStateHash() => + r'477bc54ed73067db40dc291532818108a2a37536'; + +/// See also [UseNativeHttpClientState]. +@ProviderFor(UseNativeHttpClientState) +final useNativeHttpClientStateProvider = + AutoDisposeNotifierProvider.internal( + UseNativeHttpClientState.new, + name: r'useNativeHttpClientStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$useNativeHttpClientStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$UseNativeHttpClientState = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/modules/more/settings/settings_screen.dart b/lib/modules/more/settings/settings_screen.dart index fbf4a00..e44f0ba 100644 --- a/lib/modules/more/settings/settings_screen.dart +++ b/lib/modules/more/settings/settings_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart'; @@ -46,6 +48,12 @@ class SettingsScreen extends StatelessWidget { subtitle: l10n.browse_subtitle, icon: Icons.explore_rounded, onTap: () => context.push('/browseS')), + if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) + ListTileWidget( + title: l10n.advanced, + subtitle: l10n.browse_subtitle, + icon: Icons.code_rounded, + onTap: () => context.push('/advancedScreen')), ListTileWidget( onTap: () { context.push('/about'); diff --git a/lib/router/router.dart b/lib/router/router.dart index 48aed1c..8455bb6 100644 --- a/lib/router/router.dart +++ b/lib/router/router.dart @@ -12,6 +12,7 @@ import 'package:mangayomi/modules/browse/extension/widgets/create_extension.dart import 'package:mangayomi/modules/browse/sources/sources_filter_screen.dart'; import 'package:mangayomi/modules/more/backup_and_restore/backup_and_restore.dart'; import 'package:mangayomi/modules/more/categories/categories_screen.dart'; +import 'package:mangayomi/modules/more/settings/advanced/advanced.dart'; import 'package:mangayomi/modules/more/settings/downloads/downloads_screen.dart'; import 'package:mangayomi/modules/more/settings/player/player_screen.dart'; import 'package:mangayomi/modules/more/settings/track/track.dart'; @@ -533,6 +534,19 @@ class RouterNotifier extends ChangeNotifier { ); }, ), + GoRoute( + path: "/advancedScreen", + name: "advancedScreen", + builder: (context, state) { + return const AdvancedScreen(); + }, + pageBuilder: (context, state) { + return transitionPage( + key: state.pageKey, + child: const AdvancedScreen(), + ); + }, + ), ]; } diff --git a/lib/services/http/m_client.dart b/lib/services/http/m_client.dart index 724f728..6569101 100644 --- a/lib/services/http/m_client.dart +++ b/lib/services/http/m_client.dart @@ -15,20 +15,24 @@ import 'package:mangayomi/utils/log/log.dart'; class MClient { MClient(); static Client httpClient() { - if (Platform.isAndroid) { - final engine = CronetEngine.build( - enablePublicKeyPinningBypassForLocalTrustAnchors: true, - enableHttp2: true, - enableBrotli: true, - cacheMode: CacheMode.memory, - cacheMaxSize: 5 * 1024 * 1024); - return CronetClient.fromCronetEngine(engine, closeEngine: true); - } - if (Platform.isIOS || Platform.isMacOS) { - final config = URLSessionConfiguration.ephemeralSessionConfiguration() - ..cache = URLCache.withCapacity(memoryCapacity: 5 * 1024 * 1024); - return CupertinoClient.fromSessionConfiguration(config); + if ((Platform.isAndroid || Platform.isIOS || Platform.isMacOS) && + (isar.settings.getSync(227)?.useNativeHttpClient ?? false)) { + if (Platform.isAndroid) { + final engine = CronetEngine.build( + enablePublicKeyPinningBypassForLocalTrustAnchors: true, + enableHttp2: true, + enableBrotli: true, + cacheMode: CacheMode.memory, + cacheMaxSize: 5 * 1024 * 1024); + return CronetClient.fromCronetEngine(engine, closeEngine: true); + } + if (Platform.isIOS || Platform.isMacOS) { + final config = URLSessionConfiguration.ephemeralSessionConfiguration() + ..cache = URLCache.withCapacity(memoryCapacity: 5 * 1024 * 1024); + return CupertinoClient.fromSessionConfiguration(config); + } } + return IOClient(HttpClient()); } diff --git a/pubspec.lock b/pubspec.lock index 3a86ecb..ef534df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: "5aaf60d96c4cd00fe7f21594b5ad6a1b699c80a27420f8a837f4d68473ef09e3" url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "68.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.1.0" analyzer: dependency: "direct overridden" description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: "21f1d3720fd1c70316399d5e2bccaebb415c434592d778cce8acb967b8578808" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.5.0" analyzer_plugin: dependency: transitive description: @@ -880,6 +885,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "12e8a9842b5a7390de7a781ec63d793527582398d16ea26c60fed58833c9ae79" + url: "https://pub.dev" + source: hosted + version: "0.1.0-main.0" matcher: dependency: transitive description: @@ -980,13 +993,13 @@ packages: source: git version: "1.2.4" meta: - dependency: transitive + dependency: "direct overridden" description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ef00816..7a1ae01 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,6 +98,7 @@ dependency_overrides: url: https://github.com/media-kit/media-kit.git path: media_kit_video ref: 50c510d018cc5286eb6730f3ea165290f19dc5f6 + meta: ^1.15.0 dev_dependencies: flutter_test: