feat(user-agent): add default user agent setting

This commit is contained in:
Moustapha Kodjo Amadou 2025-12-10 14:14:51 +01:00
parent 23e41373dc
commit fc49b33826
21 changed files with 215 additions and 1 deletions

View file

@ -559,5 +559,6 @@
"line_height": "Line Height", "line_height": "Line Height",
"show_scroll_percentage": "Show Scroll Percentage", "show_scroll_percentage": "Show Scroll Percentage",
"remove_extra_paragraph_spacing": "Remove Extra Paragraph Spacing", "remove_extra_paragraph_spacing": "Remove Extra Paragraph Spacing",
"select_label_color": "Select {label} Color" "select_label_color": "Select {label} Color",
"default_user_agent": "Defaul user agent"
} }

View file

@ -3430,6 +3430,12 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Select {label} Color'** /// **'Select {label} Color'**
String select_label_color(Object label); String select_label_color(Object label);
/// No description provided for @default_user_agent.
///
/// In en, this message translates to:
/// **'Defaul user agent'**
String get default_user_agent;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate

View file

@ -1775,4 +1775,7 @@ class AppLocalizationsAr extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'تحديد لون $label'; return 'تحديد لون $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1781,4 +1781,7 @@ class AppLocalizationsAs extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return '$label ৰং নিৰ্বাচন কৰক'; return '$label ৰং নিৰ্বাচন কৰক';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1796,4 +1796,7 @@ class AppLocalizationsDe extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Farbe für $label auswählen'; return 'Farbe für $label auswählen';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1775,4 +1775,7 @@ class AppLocalizationsEn extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Select $label Color'; return 'Select $label Color';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1804,6 +1804,9 @@ class AppLocalizationsEs extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Seleccionar color de $label'; return 'Seleccionar color de $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }
/// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`). /// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`).

View file

@ -1804,4 +1804,7 @@ class AppLocalizationsFr extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Sélectionner la couleur $label'; return 'Sélectionner la couleur $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1781,4 +1781,7 @@ class AppLocalizationsHi extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return '$label रंग चुनें'; return '$label रंग चुनें';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1787,4 +1787,7 @@ class AppLocalizationsId extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Pilih Warna $label'; return 'Pilih Warna $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1801,4 +1801,7 @@ class AppLocalizationsIt extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Seleziona colore $label'; return 'Seleziona colore $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1752,4 +1752,7 @@ class AppLocalizationsJa extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return '$labelの色を選択'; return '$labelの色を選択';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1799,6 +1799,9 @@ class AppLocalizationsPt extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Selecionar cor de $label'; return 'Selecionar cor de $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }
/// The translations for Portuguese, as used in Brazil (`pt_BR`). /// The translations for Portuguese, as used in Brazil (`pt_BR`).

View file

@ -1804,4 +1804,7 @@ class AppLocalizationsRu extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'Выбрать цвет $label'; return 'Выбрать цвет $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1775,4 +1775,7 @@ class AppLocalizationsTh extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return 'เลือกสี $label'; return 'เลือกสี $label';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1787,4 +1787,7 @@ class AppLocalizationsTr extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return '$label Rengini Seç'; return '$label Rengini Seç';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -1733,4 +1733,7 @@ class AppLocalizationsZh extends AppLocalizations {
String select_label_color(Object label) { String select_label_color(Object label) {
return '选择 $label 颜色'; return '选择 $label 颜色';
} }
@override
String get default_user_agent => 'Defaul user agent';
} }

View file

@ -35,6 +35,7 @@ class _GeneralStateScreen extends ConsumerState<GeneralScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context); final l10n = l10nLocalizations(context);
final customDns = ref.watch(customDnsStateProvider); final customDns = ref.watch(customDnsStateProvider);
final userAgent = ref.watch(userAgentStateProvider);
final enableDiscordRpc = ref.watch(enableDiscordRpcStateProvider); final enableDiscordRpc = ref.watch(enableDiscordRpcStateProvider);
final hideDiscordRpcInIncognito = ref.watch( final hideDiscordRpcInIncognito = ref.watch(
hideDiscordRpcInIncognitoStateProvider, hideDiscordRpcInIncognitoStateProvider,
@ -57,6 +58,14 @@ class _GeneralStateScreen extends ConsumerState<GeneralScreen> {
style: TextStyle(fontSize: 11, color: context.secondaryColor), style: TextStyle(fontSize: 11, color: context.secondaryColor),
), ),
), ),
ListTile(
onTap: () => _showDefaultUserAgentDialog(context, ref, userAgent),
title: Text(context.l10n.default_user_agent),
subtitle: Text(
userAgent,
style: TextStyle(fontSize: 11, color: context.secondaryColor),
),
),
Container( Container(
margin: const EdgeInsets.all(20.0), margin: const EdgeInsets.all(20.0),
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
@ -373,3 +382,76 @@ class _GeneralStateScreen extends ConsumerState<GeneralScreen> {
); );
} }
} }
void _showDefaultUserAgentDialog(
BuildContext context,
WidgetRef ref,
String ua,
) {
final uaController = TextEditingController(text: ua);
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
context.l10n.default_user_agent,
style: const TextStyle(fontSize: 30),
),
content: SizedBox(
width: context.width(0.8),
height: context.height(0.3),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: uaController,
autofocus: true,
decoration: InputDecoration(
hintText: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: context.width(1),
child: ElevatedButton(
onPressed: () async {
ref
.watch(userAgentStateProvider.notifier)
.set(uaController.text);
if (!context.mounted) return;
Navigator.pop(context);
},
child: Text(context.l10n.dialog_confirm),
),
),
),
],
),
),
);
},
),
);
}

View file

@ -123,3 +123,23 @@ class RpcShowCoverImageState extends _$RpcShowCoverImageState {
); );
} }
} }
@riverpod
class UserAgentState extends _$UserAgentState {
@override
String build() {
return isar.settings.getSync(227)!.userAgent!;
}
void set(String value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..userAgent = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}

View file

@ -334,3 +334,56 @@ abstract class _$RpcShowCoverImageState extends $Notifier<bool> {
element.handleValue(ref, created); element.handleValue(ref, created);
} }
} }
@ProviderFor(UserAgentState)
const userAgentStateProvider = UserAgentStateProvider._();
final class UserAgentStateProvider
extends $NotifierProvider<UserAgentState, String> {
const UserAgentStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'userAgentStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$userAgentStateHash();
@$internal
@override
UserAgentState create() => UserAgentState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(String value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<String>(value),
);
}
}
String _$userAgentStateHash() => r'e1e9ba333c5dc753813082190da4ee51ad587bb9';
abstract class _$UserAgentState extends $Notifier<String> {
String build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<String, String>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<String, String>,
String,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View file

@ -7,8 +7,10 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/modules/more/settings/general/providers/general_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/services/http/m_client.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/global_style.dart'; import 'package:mangayomi/utils/global_style.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
@ -53,6 +55,10 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
Webview? _desktopWebview; Webview? _desktopWebview;
Future<void> _runWebViewDesktop() async { Future<void> _runWebViewDesktop() async {
String? ua = ref.watch(userAgentStateProvider);
if (ua == defaultUserAgent) {
ua = null;
}
if (Platform.isLinux) { if (Platform.isLinux) {
_desktopWebview = await WebviewWindow.create(); _desktopWebview = await WebviewWindow.create();
@ -110,6 +116,7 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
webViewSettings: InAppWebViewSettings( webViewSettings: InAppWebViewSettings(
isInspectable: kDebugMode, isInspectable: kDebugMode,
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
userAgent: ua,
), ),
), ),
); );