2024-02-03 12:36:27 +03:30
|
|
|
import 'package:flutter/gestures.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:hiddify/core/localization/translations.dart';
|
|
|
|
|
import 'package:hiddify/core/model/constants.dart';
|
2024-02-15 19:39:35 +03:30
|
|
|
import 'package:hiddify/core/model/optional_range.dart';
|
2024-02-20 22:16:47 +03:30
|
|
|
import 'package:hiddify/core/widget/custom_alert_dialog.dart';
|
2024-03-02 22:53:14 +03:30
|
|
|
import 'package:hiddify/features/config_option/data/config_option_repository.dart';
|
2024-02-03 12:36:27 +03:30
|
|
|
import 'package:hiddify/features/config_option/notifier/warp_option_notifier.dart';
|
2024-03-02 22:53:14 +03:30
|
|
|
import 'package:hiddify/features/config_option/widget/preference_tile.dart';
|
2024-02-03 12:36:27 +03:30
|
|
|
import 'package:hiddify/singbox/model/singbox_config_enum.dart';
|
|
|
|
|
import 'package:hiddify/utils/uri_utils.dart';
|
|
|
|
|
import 'package:hiddify/utils/validators.dart';
|
|
|
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
|
|
|
|
|
|
class WarpOptionsTiles extends HookConsumerWidget {
|
2024-03-02 22:53:14 +03:30
|
|
|
const WarpOptionsTiles({super.key});
|
2024-02-03 12:36:27 +03:30
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final t = ref.watch(translationsProvider);
|
|
|
|
|
|
2024-02-18 12:35:11 +03:30
|
|
|
final warpOptions = ref.watch(warpOptionNotifierProvider);
|
|
|
|
|
final warpPrefaceCompleted = warpOptions.consentGiven;
|
2024-03-02 22:53:14 +03:30
|
|
|
final enableWarp = ref.watch(ConfigOptions.enableWarp);
|
|
|
|
|
final canChangeOptions = warpPrefaceCompleted && enableWarp;
|
2024-02-03 12:36:27 +03:30
|
|
|
|
2024-02-20 22:16:47 +03:30
|
|
|
ref.listen(
|
|
|
|
|
warpOptionNotifierProvider.select((value) => value.configGeneration),
|
|
|
|
|
(previous, next) async {
|
|
|
|
|
if (next case AsyncData(value: final log) when log.isNotEmpty) {
|
|
|
|
|
await CustomAlertDialog(
|
|
|
|
|
title: t.settings.config.warpConfigGenerated,
|
|
|
|
|
message: log,
|
|
|
|
|
).show(context);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
2024-02-03 12:36:27 +03:30
|
|
|
return Column(
|
|
|
|
|
children: [
|
2024-02-09 15:30:07 +03:30
|
|
|
SwitchListTile(
|
2024-02-03 12:36:27 +03:30
|
|
|
title: Text(t.settings.config.enableWarp),
|
2024-03-02 22:53:14 +03:30
|
|
|
value: enableWarp,
|
2024-02-03 12:36:27 +03:30
|
|
|
onChanged: (value) async {
|
|
|
|
|
if (!warpPrefaceCompleted) {
|
2024-02-09 15:30:07 +03:30
|
|
|
final agreed = await showDialog<bool>(
|
2024-02-03 12:36:27 +03:30
|
|
|
context: context,
|
|
|
|
|
builder: (context) => const WarpLicenseAgreementModal(),
|
|
|
|
|
);
|
|
|
|
|
if (agreed ?? false) {
|
|
|
|
|
await ref.read(warpOptionNotifierProvider.notifier).agree();
|
2024-03-02 22:53:14 +03:30
|
|
|
await ref.read(ConfigOptions.enableWarp.notifier).update(value);
|
2024-02-03 12:36:27 +03:30
|
|
|
}
|
|
|
|
|
} else {
|
2024-03-02 22:53:14 +03:30
|
|
|
await ref.read(ConfigOptions.enableWarp.notifier).update(value);
|
2024-02-03 12:36:27 +03:30
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
),
|
2024-02-18 12:35:11 +03:30
|
|
|
ListTile(
|
|
|
|
|
title: Text(t.settings.config.generateWarpConfig),
|
|
|
|
|
subtitle: canChangeOptions
|
|
|
|
|
? switch (warpOptions.configGeneration) {
|
|
|
|
|
AsyncLoading() => const LinearProgressIndicator(),
|
|
|
|
|
AsyncError() => Text(
|
|
|
|
|
t.settings.config.missingWarpConfig,
|
|
|
|
|
style:
|
|
|
|
|
TextStyle(color: Theme.of(context).colorScheme.error),
|
|
|
|
|
),
|
|
|
|
|
_ => null,
|
|
|
|
|
}
|
|
|
|
|
: null,
|
|
|
|
|
enabled: canChangeOptions,
|
|
|
|
|
onTap: () async {
|
|
|
|
|
await ref
|
|
|
|
|
.read(warpOptionNotifierProvider.notifier)
|
|
|
|
|
.generateWarpConfig();
|
|
|
|
|
},
|
|
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ChoicePreferenceWidget(
|
|
|
|
|
selected: ref.watch(ConfigOptions.warpDetourMode),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpDetourMode.notifier),
|
2024-02-03 12:36:27 +03:30
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
choices: WarpDetourMode.values,
|
|
|
|
|
title: t.settings.config.warpDetourMode,
|
|
|
|
|
presentChoice: (value) => value.present(t),
|
2024-02-03 12:36:27 +03:30
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ValuePreferenceWidget(
|
|
|
|
|
value: ref.watch(ConfigOptions.warpLicenseKey),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpLicenseKey.notifier),
|
2024-02-03 12:36:27 +03:30
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
title: t.settings.config.warpLicenseKey,
|
|
|
|
|
presentValue: (value) => value.isEmpty ? t.general.notSet : value,
|
2024-02-03 12:36:27 +03:30
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ValuePreferenceWidget(
|
|
|
|
|
value: ref.watch(ConfigOptions.warpCleanIp),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpCleanIp.notifier),
|
2024-02-03 12:36:27 +03:30
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
title: t.settings.config.warpCleanIp,
|
2024-02-03 12:36:27 +03:30
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ValuePreferenceWidget(
|
|
|
|
|
value: ref.watch(ConfigOptions.warpPort),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpPort.notifier),
|
2024-02-03 12:36:27 +03:30
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
title: t.settings.config.warpPort,
|
|
|
|
|
inputToValue: int.tryParse,
|
|
|
|
|
validateInput: isPort,
|
|
|
|
|
digitsOnly: true,
|
2024-02-03 12:36:27 +03:30
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ValuePreferenceWidget(
|
|
|
|
|
value: ref.watch(ConfigOptions.warpNoise),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpNoise.notifier),
|
2024-02-03 12:36:27 +03:30
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
title: t.settings.config.warpNoise,
|
|
|
|
|
inputToValue: (input) =>
|
|
|
|
|
OptionalRange.tryParse(input, allowEmpty: true),
|
|
|
|
|
presentValue: (value) => value.present(t),
|
|
|
|
|
formatInputValue: (value) => value.format(),
|
2024-02-03 12:36:27 +03:30
|
|
|
),
|
2024-03-02 22:53:14 +03:30
|
|
|
ValuePreferenceWidget(
|
|
|
|
|
value: ref.watch(ConfigOptions.warpNoiseDelay),
|
|
|
|
|
preferences: ref.watch(ConfigOptions.warpNoiseDelay.notifier),
|
2024-02-21 20:03:20 +01:00
|
|
|
enabled: canChangeOptions,
|
2024-03-02 22:53:14 +03:30
|
|
|
title: t.settings.config.warpNoiseDelay,
|
|
|
|
|
inputToValue: (input) =>
|
|
|
|
|
OptionalRange.tryParse(input, allowEmpty: true),
|
|
|
|
|
presentValue: (value) => value.present(t),
|
|
|
|
|
formatInputValue: (value) => value.format(),
|
|
|
|
|
),
|
2024-02-03 12:36:27 +03:30
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class WarpLicenseAgreementModal extends HookConsumerWidget {
|
|
|
|
|
const WarpLicenseAgreementModal({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final t = ref.watch(translationsProvider);
|
|
|
|
|
|
2024-02-09 15:30:07 +03:30
|
|
|
return AlertDialog(
|
2024-02-03 12:36:27 +03:30
|
|
|
title: Text(t.settings.config.warpConsent.title),
|
|
|
|
|
content: Text.rich(
|
|
|
|
|
t.settings.config.warpConsent.description(
|
|
|
|
|
tos: (text) => TextSpan(
|
|
|
|
|
text: text,
|
|
|
|
|
style: const TextStyle(color: Colors.blue),
|
|
|
|
|
recognizer: TapGestureRecognizer()
|
|
|
|
|
..onTap = () async {
|
|
|
|
|
await UriUtils.tryLaunch(
|
|
|
|
|
Uri.parse(Constants.cfWarpTermsOfService),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
privacy: (text) => TextSpan(
|
|
|
|
|
text: text,
|
|
|
|
|
style: const TextStyle(color: Colors.blue),
|
|
|
|
|
recognizer: TapGestureRecognizer()
|
|
|
|
|
..onTap = () async {
|
|
|
|
|
await UriUtils.tryLaunch(
|
|
|
|
|
Uri.parse(Constants.cfWarpPrivacyPolicy),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
actions: [
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Navigator.of(context).pop(false);
|
|
|
|
|
},
|
|
|
|
|
child: Text(t.general.decline),
|
|
|
|
|
),
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Navigator.of(context).pop(true);
|
|
|
|
|
},
|
|
|
|
|
child: Text(t.general.agree),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|