Add export config to clipboard
This commit is contained in:
@@ -90,6 +90,27 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<CoreServiceFailure, String> generateConfig(
|
||||
String fileName,
|
||||
) {
|
||||
return exceptionHandler(
|
||||
() {
|
||||
final configPath = filesEditor.configPath(fileName);
|
||||
final options = configOptions();
|
||||
return setup()
|
||||
.andThen(() => changeConfigOptions(options))
|
||||
.andThen(
|
||||
() => singbox
|
||||
.generateConfig(configPath)
|
||||
.mapLeft(CoreServiceFailure.other),
|
||||
)
|
||||
.run();
|
||||
},
|
||||
CoreServiceFailure.unexpected,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<CoreServiceFailure, Unit> start(
|
||||
String fileName,
|
||||
|
||||
@@ -18,6 +18,10 @@ abstract interface class SingboxFacade {
|
||||
ConfigOptions options,
|
||||
);
|
||||
|
||||
TaskEither<CoreServiceFailure, String> generateConfig(
|
||||
String fileName,
|
||||
);
|
||||
|
||||
TaskEither<CoreServiceFailure, Unit> start(
|
||||
String fileName,
|
||||
bool disableMemoryLimit,
|
||||
|
||||
@@ -254,6 +254,14 @@ class ProfileActionsMenu extends HookConsumerWidget {
|
||||
initialOnSuccess: () =>
|
||||
CustomToast.success(t.profile.update.successMsg).show(context),
|
||||
);
|
||||
final exportConfigMutation = useMutation(
|
||||
initialOnFailure: (err) {
|
||||
CustomToast.error(t.presentShortError(err)).show(context);
|
||||
},
|
||||
initialOnSuccess: () =>
|
||||
CustomToast.success(t.profile.share.exportConfigToClipboardSuccess)
|
||||
.show(context),
|
||||
);
|
||||
final deleteProfileMutation = useMutation(
|
||||
initialOnFailure: (err) {
|
||||
CustomAlertDialog.fromErr(t.presentError(err)).show(context);
|
||||
@@ -278,6 +286,25 @@ class ProfileActionsMenu extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
SubmenuButton(
|
||||
menuChildren: [
|
||||
MenuItemButton(
|
||||
child: Text(t.profile.share.exportConfigToClipboard),
|
||||
onPressed: () async {
|
||||
if (exportConfigMutation.state.isInProgress) {
|
||||
return;
|
||||
}
|
||||
exportConfigMutation.setFuture(
|
||||
ref
|
||||
.read(profilesNotifierProvider.notifier)
|
||||
.exportConfigToClipboard(profile),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
leadingIcon: const Icon(Icons.share),
|
||||
child: Text(t.profile.share.buttonText),
|
||||
),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.edit),
|
||||
child: Text(t.profile.edit.buttonTxt),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/prefs/prefs.dart';
|
||||
import 'package:hiddify/data/data_providers.dart';
|
||||
@@ -124,4 +125,16 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger {
|
||||
},
|
||||
).run();
|
||||
}
|
||||
|
||||
Future<void> exportConfigToClipboard(Profile profile) async {
|
||||
await ref.read(coreFacadeProvider).generateConfig(profile.id).match(
|
||||
(err) {
|
||||
loggy.warning('error generating config', err);
|
||||
throw err;
|
||||
},
|
||||
(configJson) async {
|
||||
await Clipboard.setData(ClipboardData(text: configJson));
|
||||
},
|
||||
).run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,6 +934,21 @@ class SingboxNativeLibrary {
|
||||
late final _changeConfigOptions = _changeConfigOptionsPtr
|
||||
.asFunction<ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
ffi.Pointer<ffi.Char> generateConfig(
|
||||
ffi.Pointer<ffi.Char> path,
|
||||
) {
|
||||
return _generateConfig(
|
||||
path,
|
||||
);
|
||||
}
|
||||
|
||||
late final _generateConfigPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<ffi.Char> Function(
|
||||
ffi.Pointer<ffi.Char>)>>('generateConfig');
|
||||
late final _generateConfig = _generateConfigPtr
|
||||
.asFunction<ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
ffi.Pointer<ffi.Char> start(
|
||||
ffi.Pointer<ffi.Char> configPath,
|
||||
int disableMemoryLimit,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:combine/combine.dart';
|
||||
import 'package:dartx/dartx.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/domain/connectivity/connectivity.dart';
|
||||
@@ -137,6 +138,28 @@ class FFISingboxService
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<String, String> generateConfig(
|
||||
String path,
|
||||
) {
|
||||
return TaskEither(
|
||||
() => CombineWorker().execute(
|
||||
() {
|
||||
final response = _box
|
||||
.generateConfig(
|
||||
path.toNativeUtf8().cast(),
|
||||
)
|
||||
.cast<Utf8>()
|
||||
.toDartString();
|
||||
if (response.startsWith("error")) {
|
||||
return left(response.removePrefix("error"));
|
||||
}
|
||||
return right(response);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<String, Unit> start(String configPath, bool disableMemoryLimit) {
|
||||
loggy.debug("starting, memory limit: [${!disableMemoryLimit}]");
|
||||
|
||||
@@ -73,6 +73,24 @@ class MobileSingboxService
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<String, String> generateConfig(
|
||||
String path,
|
||||
) {
|
||||
return TaskEither(
|
||||
() async {
|
||||
final configJson = await _methodChannel.invokeMethod<String>(
|
||||
"generate_config",
|
||||
{"path": path},
|
||||
);
|
||||
if (configJson == null || configJson.isEmpty) {
|
||||
return left("null response");
|
||||
}
|
||||
return right(configJson);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TaskEither<String, Unit> start(String configPath, bool disableMemoryLimit) {
|
||||
return TaskEither(
|
||||
|
||||
@@ -33,6 +33,10 @@ abstract interface class SingboxService {
|
||||
|
||||
TaskEither<String, Unit> changeConfigOptions(ConfigOptions options);
|
||||
|
||||
TaskEither<String, String> generateConfig(
|
||||
String path,
|
||||
);
|
||||
|
||||
TaskEither<String, Unit> start(String configPath, bool disableMemoryLimit);
|
||||
|
||||
TaskEither<String, Unit> stop();
|
||||
|
||||
Reference in New Issue
Block a user