mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: webdav
Closes #432 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -7,12 +7,14 @@ import 'package:PiliPlus/pages/setting/privacy_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/recommend_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/style_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/video_setting.dart';
|
||||
import 'package:PiliPlus/pages/webdav/view.dart';
|
||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
import 'widgets/multi_select_dialog.dart';
|
||||
|
||||
@@ -84,6 +86,11 @@ class _SettingPageState extends State<SettingPage> {
|
||||
subtitle: '震动、搜索、收藏、ai、评论、动态、代理、更新检查等',
|
||||
icon: Icons.extension_outlined,
|
||||
),
|
||||
_SettingsModel(
|
||||
name: 'webdavSetting',
|
||||
title: 'WebDAV 设置',
|
||||
icon: MdiIcons.databaseCogOutline,
|
||||
),
|
||||
_SettingsModel(
|
||||
name: 'about',
|
||||
title: '关于',
|
||||
@@ -104,6 +111,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
'playSetting' => '播放器设置',
|
||||
'styleSetting' => '外观设置',
|
||||
'extraSetting' => '其它设置',
|
||||
'webdavSetting' => 'WebDAV 设置',
|
||||
'about' => '关于',
|
||||
_ => '设置',
|
||||
}),
|
||||
@@ -127,6 +135,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
'playSetting' => PlaySetting(showAppBar: false),
|
||||
'styleSetting' => StyleSetting(showAppBar: false),
|
||||
'extraSetting' => ExtraSetting(showAppBar: false),
|
||||
'webdavSetting' => WebDavSettingPage(showAppBar: false),
|
||||
'about' => AboutPage(showAppBar: false),
|
||||
_ => const SizedBox.shrink(),
|
||||
},
|
||||
|
||||
134
lib/pages/webdav/view.dart
Normal file
134
lib/pages/webdav/view.dart
Normal file
@@ -0,0 +1,134 @@
|
||||
import 'package:PiliPlus/pages/webdav/webdav.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
|
||||
class WebDavSettingPage extends StatefulWidget {
|
||||
const WebDavSettingPage({
|
||||
super.key,
|
||||
this.showAppBar,
|
||||
});
|
||||
|
||||
final bool? showAppBar;
|
||||
|
||||
@override
|
||||
State<WebDavSettingPage> createState() => _WebDavSettingPageState();
|
||||
}
|
||||
|
||||
class _WebDavSettingPageState extends State<WebDavSettingPage> {
|
||||
final _uriCtr = TextEditingController(text: GStorage.webdavUri);
|
||||
final _usernameCtr = TextEditingController(text: GStorage.webdavUsername);
|
||||
final _passwordCtr = TextEditingController(text: GStorage.webdavPassword);
|
||||
final _directoryCtr = TextEditingController(text: GStorage.webdavDirectory);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_uriCtr.dispose();
|
||||
_usernameCtr.dispose();
|
||||
_passwordCtr.dispose();
|
||||
_directoryCtr.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
EdgeInsets padding = MediaQuery.paddingOf(context);
|
||||
return Scaffold(
|
||||
appBar: widget.showAppBar == false
|
||||
? null
|
||||
: AppBar(title: const Text('WebDAV 设置')),
|
||||
body: ListView(
|
||||
padding: padding.copyWith(
|
||||
top: 20,
|
||||
left: padding.left + 20,
|
||||
right: padding.right + 20,
|
||||
bottom: padding.bottom + 90,
|
||||
),
|
||||
children: [
|
||||
TextField(
|
||||
controller: _uriCtr,
|
||||
decoration: const InputDecoration(
|
||||
labelText: '地址',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: _usernameCtr,
|
||||
decoration: const InputDecoration(
|
||||
labelText: '用户',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: _passwordCtr,
|
||||
decoration: const InputDecoration(
|
||||
labelText: '密码',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: _directoryCtr,
|
||||
decoration: const InputDecoration(
|
||||
labelText: '路径',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: WebDav().backup,
|
||||
child: const Text('备份设置'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: WebDav().restore,
|
||||
child: const Text('恢复设置'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.save),
|
||||
onPressed: () async {
|
||||
if (_uriCtr.text.isEmpty) {
|
||||
SmartDialog.showToast('地址不能为空');
|
||||
return;
|
||||
}
|
||||
await GStorage.setting.put(SettingBoxKey.webdavUri, _uriCtr.text);
|
||||
await GStorage.setting
|
||||
.put(SettingBoxKey.webdavUsername, _usernameCtr.text);
|
||||
await GStorage.setting
|
||||
.put(SettingBoxKey.webdavPassword, _passwordCtr.text);
|
||||
await GStorage.setting
|
||||
.put(SettingBoxKey.webdavDirectory, _directoryCtr.text);
|
||||
try {
|
||||
final res = await WebDav().init();
|
||||
SmartDialog.showToast('配置${res ? '成功' : '失败'}');
|
||||
} catch (e) {
|
||||
SmartDialog.showToast('配置失败: ${e.toString()}');
|
||||
return;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
88
lib/pages/webdav/webdav.dart
Normal file
88
lib/pages/webdav/webdav.dart
Normal file
@@ -0,0 +1,88 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:webdav_client/webdav_client.dart' as webdav;
|
||||
|
||||
class WebDav {
|
||||
late String _webDavUri;
|
||||
late String _webDavUsername;
|
||||
late String _webDavPassword;
|
||||
late String _webdavDirectory;
|
||||
|
||||
webdav.Client? _client;
|
||||
|
||||
WebDav._internal();
|
||||
static final WebDav _instance = WebDav._internal();
|
||||
factory WebDav() => _instance;
|
||||
|
||||
Future<bool> init() async {
|
||||
_webDavUri = GStorage.webdavUri;
|
||||
_webDavUsername = GStorage.webdavUsername;
|
||||
_webDavPassword = GStorage.webdavPassword;
|
||||
_webdavDirectory = GStorage.webdavDirectory;
|
||||
if (_webdavDirectory.endsWith('/').not) {
|
||||
_webdavDirectory += '/';
|
||||
}
|
||||
_webdavDirectory += 'PiliPlus';
|
||||
|
||||
try {
|
||||
_client = null;
|
||||
final client = webdav.newClient(
|
||||
_webDavUri,
|
||||
user: _webDavUsername,
|
||||
password: _webDavPassword,
|
||||
)
|
||||
..setHeaders({'accept-charset': 'utf-8'})
|
||||
..setConnectTimeout(4000)
|
||||
..setReceiveTimeout(4000)
|
||||
..setSendTimeout(4000);
|
||||
|
||||
await client.mkdirAll(_webdavDirectory);
|
||||
|
||||
_client = client;
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future backup() async {
|
||||
if (_client == null) {
|
||||
if (await init() == false) {
|
||||
SmartDialog.showToast('备份失败,请检查配置');
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
final path = '$_webdavDirectory/piliplus_settings.json';
|
||||
final file = File(path);
|
||||
if (await file.exists()) {
|
||||
await file.delete();
|
||||
}
|
||||
String data = await GStorage.exportAllSettings();
|
||||
await _client!.write(path, utf8.encode(data));
|
||||
SmartDialog.showToast('备份成功');
|
||||
} catch (e) {
|
||||
SmartDialog.showToast('备份失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future restore() async {
|
||||
if (_client == null) {
|
||||
if (await init() == false) {
|
||||
SmartDialog.showToast('恢复失败,请检查配置');
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
final path = '$_webdavDirectory/piliplus_settings.json';
|
||||
final data = await _client!.read(path);
|
||||
await GStorage.importAllSettings(utf8.decode(data));
|
||||
SmartDialog.showToast('恢复成功');
|
||||
} catch (e) {
|
||||
SmartDialog.showToast('恢复失败: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:PiliPlus/pages/setting/sponsor_block_page.dart';
|
||||
import 'package:PiliPlus/pages/setting/view.dart';
|
||||
import 'package:PiliPlus/pages/video/detail/introduction/widgets/create_fav_page.dart';
|
||||
import 'package:PiliPlus/pages/video/detail/view_v.dart';
|
||||
import 'package:PiliPlus/pages/webdav/view.dart';
|
||||
import 'package:PiliPlus/pages/webview/webview_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -175,6 +176,8 @@ class Routes {
|
||||
name: '/navbarSetting', page: () => const NavigationBarSetPage()),
|
||||
CustomGetPage(
|
||||
name: '/settingsSearch', page: () => const SettingsSearchPage()),
|
||||
CustomGetPage(
|
||||
name: '/webdavSetting', page: () => const WebDavSettingPage()),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -451,6 +451,18 @@ class GStorage {
|
||||
static bool get navSearchStreamDebounce => GStorage.setting
|
||||
.get(SettingBoxKey.navSearchStreamDebounce, defaultValue: false);
|
||||
|
||||
static String get webdavUri =>
|
||||
GStorage.setting.get(SettingBoxKey.webdavUri, defaultValue: '');
|
||||
|
||||
static String get webdavUsername =>
|
||||
GStorage.setting.get(SettingBoxKey.webdavUsername, defaultValue: '');
|
||||
|
||||
static String get webdavPassword =>
|
||||
GStorage.setting.get(SettingBoxKey.webdavPassword, defaultValue: '');
|
||||
|
||||
static String get webdavDirectory =>
|
||||
GStorage.setting.get(SettingBoxKey.webdavDirectory, defaultValue: '/');
|
||||
|
||||
static List<double> get dynamicDetailRatio => List<double>.from(setting
|
||||
.get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0]));
|
||||
|
||||
@@ -737,6 +749,12 @@ class SettingBoxKey {
|
||||
recordSearchHistory = 'recordSearchHistory',
|
||||
navSearchStreamDebounce = 'navSearchStreamDebounce',
|
||||
|
||||
// WebDAV
|
||||
webdavUri = 'webdavUri',
|
||||
webdavUsername = 'webdavUsername',
|
||||
webdavPassword = 'webdavPassword',
|
||||
webdavDirectory = 'webdavDirectory',
|
||||
|
||||
// Sponsor Block
|
||||
enableSponsorBlock = 'enableSponsorBlock',
|
||||
blockSettings = 'blockSettings',
|
||||
|
||||
@@ -2022,6 +2022,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
webdav_client:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webdav_client
|
||||
sha256: "682fffc50b61dc0e8f46717171db03bf9caaa17347be41c0c91e297553bf86b2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
webview_cookie_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -189,6 +189,7 @@ dependencies:
|
||||
fl_chart: ^0.69.2
|
||||
synchronized: ^3.3.0
|
||||
document_file_save_plus: ^2.0.0
|
||||
webdav_client: ^1.2.2
|
||||
|
||||
dependency_overrides:
|
||||
screen_brightness: ^2.0.1
|
||||
|
||||
Reference in New Issue
Block a user