mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-08 09:30:27 +00:00
feat: support drag torrent file (#42)
This commit is contained in:
1 parent
77e59f7376
commit
e9442edd94
9 files changed
+122
-79
No files matched your search
@@ -6,6 +6,10 @@ Locale toLocale(String key) {
|
||||
return Locale(arr[0], arr[1]);
|
||||
}
|
||||
|
||||
String getLocaleKey(Locale locale) {
|
||||
return '${locale.languageCode}_${locale.countryCode}';
|
||||
}
|
||||
|
||||
final messages = _Messages();
|
||||
const fallbackLocale = Locale('en', 'US');
|
||||
|
||||
@@ -21,7 +25,8 @@ class _Messages extends Translations {
|
||||
'create.title': '创建任务',
|
||||
'create.downloadLink': '下载链接',
|
||||
'create.downloadLinkValid': '请输入下载链接',
|
||||
'create.downloadLinkHit': '请输入下载链接,支持 HTTP/HTTPS/MAGNET',
|
||||
'create.downloadLinkHit': '请输入下载链接,支持 HTTP/HTTPS/MAGNET@append',
|
||||
'create.downloadLinkHitDesktop': ',也可以直接拖拽种子文件到此处',
|
||||
'create.download': '下载',
|
||||
'create.error.noStoragePermission': '需要开启存储权限',
|
||||
'create.selectDir': '选择目录',
|
||||
@@ -51,7 +56,9 @@ class _Messages extends Translations {
|
||||
'create.downloadLink': 'Download Link',
|
||||
'create.downloadLinkValid': 'Please enter the download link',
|
||||
'create.downloadLinkHit':
|
||||
'Please enter the download link, HTTP/HTTPS/MAGNET supported',
|
||||
'Please enter the download link, HTTP/HTTPS/MAGNET supported@append',
|
||||
'create.downloadLinkHitDesktop':
|
||||
', or drag the torrent file here directly',
|
||||
'create.download': 'Download',
|
||||
'create.error.noStoragePermission': 'Storage permission required',
|
||||
'create.selectDir': 'Select Directory',
|
||||
|
||||
@@ -26,7 +26,7 @@ void main() async {
|
||||
darkTheme: GopeedTheme.dark,
|
||||
themeMode: Setting.instance.themeMode,
|
||||
translations: messages,
|
||||
locale: Setting.instance.locale,
|
||||
locale: toLocale(Setting.instance.locale),
|
||||
fallbackLocale: fallbackLocale,
|
||||
getPages: Routes.routes,
|
||||
));
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CreateController extends GetxController {
|
||||
var currentIndex = 0.obs;
|
||||
}
|
||||
class CreateController extends GetxController {}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:desktop_drop/desktop_drop.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../api/api.dart';
|
||||
@@ -32,65 +33,75 @@ class CreateView extends GetView<CreateController> {
|
||||
actions: [Container()],
|
||||
title: Text('create.title'.tr),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
|
||||
child: Form(
|
||||
key: _resolveFormKey,
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
autofocus: true,
|
||||
controller: _urlController,
|
||||
minLines: 1,
|
||||
maxLines: 15,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'create.downloadLinkHit'.tr,
|
||||
labelText: 'create.downloadLink'.tr,
|
||||
icon: const Icon(Icons.link)),
|
||||
validator: (v) {
|
||||
return v!.trim().isNotEmpty
|
||||
? null
|
||||
: 'create.downloadLinkValid'.tr;
|
||||
}),
|
||||
// 登录按钮
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
width: 150,
|
||||
height: 40,
|
||||
),
|
||||
child: RoundedLoadingButton(
|
||||
color: Get.theme.colorScheme.secondary,
|
||||
onPressed: () async {
|
||||
if (_resolveFormKey.currentState!.validate()) {
|
||||
_confirmController.start();
|
||||
try {
|
||||
final res = await resolve(Request(
|
||||
url: _urlController.text,
|
||||
));
|
||||
await _showResolveDialog(res);
|
||||
} catch (e) {
|
||||
Get.snackbar('error'.tr, e.toString());
|
||||
} finally {
|
||||
_confirmController.reset();
|
||||
body: DropTarget(
|
||||
onDragDone: (details) {
|
||||
_urlController.text = details.files[0].path;
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
|
||||
child: Form(
|
||||
key: _resolveFormKey,
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
autofocus: true,
|
||||
controller: _urlController,
|
||||
minLines: 1,
|
||||
maxLines: 15,
|
||||
decoration: InputDecoration(
|
||||
hintText: _hitText(),
|
||||
labelText: 'create.downloadLink'.tr,
|
||||
icon: const Icon(Icons.link)),
|
||||
validator: (v) {
|
||||
return v!.trim().isNotEmpty
|
||||
? null
|
||||
: 'create.downloadLinkValid'.tr;
|
||||
}),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
width: 150,
|
||||
height: 40,
|
||||
),
|
||||
child: RoundedLoadingButton(
|
||||
color: Get.theme.colorScheme.secondary,
|
||||
onPressed: () async {
|
||||
if (_resolveFormKey.currentState!.validate()) {
|
||||
_confirmController.start();
|
||||
try {
|
||||
final res = await resolve(Request(
|
||||
url: _urlController.text,
|
||||
));
|
||||
await _showResolveDialog(res);
|
||||
} catch (e) {
|
||||
Get.snackbar('error'.tr, e.toString());
|
||||
} finally {
|
||||
_confirmController.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
controller: _confirmController,
|
||||
child: Text('confirm'.tr),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
},
|
||||
controller: _confirmController,
|
||||
child: Text('confirm'.tr),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _hitText() {
|
||||
return 'create.downloadLinkHit'.trParams({
|
||||
'append': Util.isDesktop() ? 'create.downloadLinkHitDesktop'.tr : '',
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _showResolveDialog(Resource res) async {
|
||||
final createFormKey = GlobalKey<FormState>();
|
||||
final pathController =
|
||||
|
||||
@@ -16,8 +16,15 @@ class SettingView extends GetView<SettingController> {
|
||||
Widget build(BuildContext context) {
|
||||
Timer? timer;
|
||||
debounceSave() {
|
||||
var completer = Completer<void>();
|
||||
timer?.cancel();
|
||||
timer = Timer(const Duration(milliseconds: 500), Setting.instance.save);
|
||||
timer = Timer(const Duration(milliseconds: 500), () {
|
||||
Setting.instance
|
||||
.save()
|
||||
.then(completer.complete)
|
||||
.onError(completer.completeError);
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
@@ -39,12 +46,12 @@ class SettingView extends GetView<SettingController> {
|
||||
() => DropdownButton<ThemeMode>(
|
||||
value: controller.setting.value.themeMode,
|
||||
isDense: true,
|
||||
onChanged: (value) {
|
||||
onChanged: (value) async {
|
||||
controller.setting.value.themeMode = value!;
|
||||
controller.clearTapStatus();
|
||||
Get.changeThemeMode(value);
|
||||
|
||||
debounceSave();
|
||||
await debounceSave();
|
||||
},
|
||||
items: ThemeMode.values
|
||||
.map((e) => DropdownMenuItem<ThemeMode>(
|
||||
@@ -57,14 +64,14 @@ class SettingView extends GetView<SettingController> {
|
||||
() => controller.setting.value.downloadDir, () {
|
||||
final downloadDirController = TextEditingController(
|
||||
text: controller.setting.value.downloadDir);
|
||||
downloadDirController.addListener(() {
|
||||
downloadDirController.addListener(() async {
|
||||
if (downloadDirController.text !=
|
||||
controller.setting.value.downloadDir) {
|
||||
controller.setting.value.downloadDir =
|
||||
downloadDirController.text;
|
||||
controller.clearTapStatus();
|
||||
|
||||
debounceSave();
|
||||
await debounceSave();
|
||||
}
|
||||
});
|
||||
return DirectorySelector(
|
||||
@@ -77,14 +84,14 @@ class SettingView extends GetView<SettingController> {
|
||||
() {
|
||||
final connectionsController = TextEditingController(
|
||||
text: controller.setting.value.connections.toString());
|
||||
connectionsController.addListener(() {
|
||||
connectionsController.addListener(() async {
|
||||
if (connectionsController.text.isNotEmpty &&
|
||||
connectionsController.text !=
|
||||
controller.setting.value.connections.toString()) {
|
||||
controller.setting.value.connections =
|
||||
int.parse(connectionsController.text);
|
||||
|
||||
debounceSave();
|
||||
await debounceSave();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,20 +107,20 @@ class SettingView extends GetView<SettingController> {
|
||||
_ConfigItem(
|
||||
'setting.locale'.tr,
|
||||
() => _getLocaleName(controller.setting.value.locale),
|
||||
() => DropdownButton<Locale>(
|
||||
() => DropdownButton<String>(
|
||||
value: controller.setting.value.locale,
|
||||
isDense: true,
|
||||
onChanged: (value) {
|
||||
onChanged: (value) async {
|
||||
controller.setting.value.locale = value!;
|
||||
controller.clearTapStatus();
|
||||
Get.updateLocale(value);
|
||||
Get.updateLocale(toLocale(value));
|
||||
|
||||
debounceSave();
|
||||
await debounceSave();
|
||||
},
|
||||
items: _getLocales()
|
||||
.map((e) => DropdownMenuItem<Locale>(
|
||||
value: toLocale(e
|
||||
.substring(_settingLocaleKey.length)),
|
||||
.map((e) => DropdownMenuItem<String>(
|
||||
value:
|
||||
e.substring(_settingLocaleKey.length),
|
||||
child: Text(e.tr),
|
||||
))
|
||||
.toList(),
|
||||
@@ -164,14 +171,18 @@ class SettingView extends GetView<SettingController> {
|
||||
final _settingLocaleKey = 'setting.locale.';
|
||||
|
||||
List<String> _getLocales() {
|
||||
return messages.keys[fallbackLocale.toString()]!.entries
|
||||
return messages.keys[getLocaleKey(fallbackLocale)]!.entries
|
||||
.where((e) => e.key.startsWith(_settingLocaleKey))
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
}
|
||||
|
||||
String _getLocaleName(Locale locale) {
|
||||
return '$_settingLocaleKey${locale.toString()}'.tr;
|
||||
String _getLocaleName(String locale) {
|
||||
final localeKey = '$_settingLocaleKey${locale.toString()}';
|
||||
if (messages.keys[locale]?.containsKey(localeKey) ?? false) {
|
||||
return localeKey.tr;
|
||||
}
|
||||
return '$_settingLocaleKey$locale'.tr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,16 @@ class Setting {
|
||||
int port = 0;
|
||||
int connections = 0;
|
||||
String downloadDir = "";
|
||||
ThemeMode themeMode = ThemeMode.system;
|
||||
Locale locale = ui.window.locale;
|
||||
late ThemeMode themeMode;
|
||||
late String locale;
|
||||
|
||||
// singleton pattern
|
||||
static Setting? _instance;
|
||||
|
||||
static Setting get instance {
|
||||
_instance ??= Setting._internal();
|
||||
_instance!.themeMode = ThemeMode.system;
|
||||
_instance!.locale = getLocaleKey(ui.window.locale);
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
@@ -39,7 +41,7 @@ class Setting {
|
||||
}
|
||||
final locale = config.extra?['locale'];
|
||||
if (locale != null) {
|
||||
this.locale = toLocale(locale);
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
if (Util.isWeb()) {
|
||||
@@ -67,7 +69,7 @@ class Setting {
|
||||
downloadDir: downloadDir,
|
||||
extra: {
|
||||
'themeMode': themeMode.name,
|
||||
'locale': locale.toString(),
|
||||
'locale': locale,
|
||||
},
|
||||
);
|
||||
await putConfig(config);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
PODS:
|
||||
- desktop_drop (0.0.1):
|
||||
- FlutterMacOS
|
||||
- file_selector_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
@@ -12,6 +14,7 @@ PODS:
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`)
|
||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- macos_secure_bookmarks (from `Flutter/ephemeral/.symlinks/plugins/macos_secure_bookmarks/macos`)
|
||||
@@ -20,6 +23,8 @@ DEPENDENCIES:
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
desktop_drop:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos
|
||||
file_selector_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
|
||||
FlutterMacOS:
|
||||
@@ -34,6 +39,7 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
|
||||
file_selector_macos: f1b08a781e66103e3ba279fd5d4024a2478b3af6
|
||||
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
|
||||
macos_secure_bookmarks: cff041c4b377fa00941bb901aaec4d27fac5edf2
|
||||
|
||||
@@ -183,6 +183,13 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
desktop_drop:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: desktop_drop
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -49,6 +49,7 @@ dependencies:
|
||||
permission_handler: ^10.1.0
|
||||
external_path: ^1.0.3
|
||||
logger: ^1.1.0
|
||||
desktop_drop: ^0.3.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in new issue
Block a user