feat: change storage setting

This commit is contained in:
Simon Ding
2024-07-14 18:16:17 +08:00
parent 1edbd8fe6e
commit 6a5ff9707e
30 changed files with 995 additions and 857 deletions

View File

@@ -115,7 +115,23 @@ class MyApp extends StatelessWidget {
return ProviderScope(
child: MaterialApp.router(
title: 'Polaris',
theme: ThemeData(
// Define the default TextTheme. Use this to specify the default
// text styling for headlines, titles, bodies of text, and more.
// textTheme: const TextTheme(
// bodyLarge: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// bodyMedium: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// bodySmall: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// titleLarge: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// titleMedium: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// titleSmall: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// labelLarge: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// labelMedium: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// labelSmall: TextStyle(fontFamilyFallback: ["PingFang SC", "Heiti SC"]),
// ),
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue, brightness: Brightness.dark),
useMaterial3: true,

View File

@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:quiver/strings.dart';
@@ -246,30 +247,21 @@ class StorageSettingData extends AsyncNotifier<List<Storage>> {
}
class Storage {
Storage({
this.id,
this.name,
this.implementation,
this.path,
this.user,
this.password,
});
Storage({this.id, this.name, this.implementation, this.settings, this.isDefault});
final int? id;
final String? name;
final String? implementation;
final String? path;
final String? user;
final String? password;
final Map<String, dynamic>? settings;
final bool? isDefault;
factory Storage.fromJson(Map<String, dynamic> json) {
factory Storage.fromJson(Map<String, dynamic> json1) {
return Storage(
id: json["id"],
name: json["name"],
implementation: json["implementation"],
path: json["path"],
user: json["user"],
password: json["password"],
id: json1["id"],
name: json1["name"],
implementation: json1["implementation"],
settings: json.decode(json1["settings"]),
isDefault: json1["default"]
);
}
@@ -277,8 +269,7 @@ class Storage {
"id": id,
"name": name,
"implementation": implementation,
"path": path,
"user": user,
"password": password,
"settings": settings,
"default": isDefault,
};
}

View File

@@ -106,73 +106,80 @@ class _SearchPageState extends ConsumerState<SearchPage> {
}
Future<void> _showSubmitDialog(BuildContext context, SearchResult item) {
String _resSelected = "1080p";
int _storageSelected = 0;
var storage = ref.watch(storageSettingProvider);
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('添加剧集: ${item.name}'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownMenu(
label: const Text("清晰度"),
initialSelection: _resSelected,
dropdownMenuEntries: const [
DropdownMenuEntry(value: "720p", label: "720p"),
DropdownMenuEntry(value: "1080p", label: "1080p"),
DropdownMenuEntry(value: "4k", label: "4k"),
],
onSelected: (value) {
setState(() {
_resSelected = value!;
});
},
),
storage.when(
data: (v) {
return DropdownMenu(
label: const Text("存储位置"),
initialSelection: _storageSelected,
dropdownMenuEntries: v
.map((s) =>
DropdownMenuEntry(label: s.name!, value: s.id))
.toList(),
onSelected: (value) {
setState(() {
_storageSelected = value!;
});
return StatefulBuilder(
builder: (context, setState) {
String _resSelected = "1080p";
Storage? _storageSelected;
var storage = ref.watch(storageSettingProvider);
return AlertDialog(
title: Text('添加剧集: ${item.name}'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownMenu(
label: const Text("清晰度"),
initialSelection: _resSelected,
dropdownMenuEntries: const [
DropdownMenuEntry(value: "720p", label: "720p"),
DropdownMenuEntry(value: "1080p", label: "1080p"),
DropdownMenuEntry(value: "4k", label: "4k"),
],
onSelected: (value) {
setState(() {
_resSelected = value!;
});
},
),
storage.when(
data: (v) {
return DropdownMenu(
label: const Text("存储位置"),
initialSelection: _storageSelected,
dropdownMenuEntries: v
.map((s) =>
DropdownMenuEntry(label: s.name!, value: s))
.toList(),
onSelected: (value) {
setState(() {
_storageSelected = value;
});
},
);
},
);
error: (err, trace) => Text("$err"),
loading: () => const MyProgressIndicator()),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
error: (err, trace) => Text("$err"),
loading: () => MyProgressIndicator()),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('确定'),
onPressed: () {
ref.read(searchPageDataProvider.notifier).submit2Watchlist(
item.id!, _storageSelected, _resSelected);
Navigator.of(context).pop();
},
),
],
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('确定'),
onPressed: () {
ref
.read(searchPageDataProvider.notifier)
.submit2Watchlist(
item.id!, _storageSelected!.id!, _resSelected);
Navigator.of(context).pop();
},
),
],
);
},
);
});
}

View File

@@ -473,84 +473,121 @@ class _SystemSettingsPageState extends ConsumerState<SystemSettingsPage> {
Future<void> showStorageDetails(
AsyncSnapshot<void> snapshot, BuildContext context, Storage s) {
var nameController = TextEditingController(text: s.name);
var implController = TextEditingController(
text: isBlank(s.implementation) ? "transmission" : s.implementation);
var pathController = TextEditingController(text: s.path);
var userController = TextEditingController(text: s.user);
var passController = TextEditingController(text: s.password);
return showDialog<void>(
context: context,
barrierDismissible: true, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('存储'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
TextField(
decoration: const InputDecoration(labelText: "名称"),
controller: nameController,
),
TextField(
decoration: const InputDecoration(labelText: "实现"),
controller: implController,
),
TextField(
decoration: const InputDecoration(labelText: "路径"),
controller: pathController,
),
TextField(
decoration: const InputDecoration(labelText: "用户"),
controller: userController,
),
TextField(
decoration: const InputDecoration(labelText: "密码"),
controller: passController,
),
],
),
),
actions: <Widget>[
s.id == null
? const Text("")
: TextButton(
onPressed: () {
var f = ref
.read(storageSettingProvider.notifier)
.deleteStorage(s.id!);
var nameController = TextEditingController(text: s.name);
var pathController = TextEditingController();
var urlController = TextEditingController();
var userController = TextEditingController();
var passController = TextEditingController();
if (s.settings != null) {
pathController.text = s.settings!["path"];
urlController.text = s.settings!["url"];
userController.text = s.settings!["user"];
passController.text = s.settings!["password"];
}
String _selectImpl = s.implementation == null? "local": s.implementation!;
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
title: const Text('存储'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
DropdownMenu(
label: const Text("实现"),
onSelected: (value) {
setState(() {
_pendingStorage = f;
_selectImpl = value!;
});
if (!showError(snapshot)) {
Navigator.of(context).pop();
}
},
child: const Text('删除')),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消')),
TextButton(
child: const Text('确定'),
onPressed: () {
var f = ref.read(storageSettingProvider.notifier).addStorage(
Storage(
name: nameController.text,
implementation: implController.text,
path: pathController.text,
user: userController.text,
password: passController.text));
setState(() {
_pendingStorage = f;
});
if (!showError(snapshot)) {
Navigator.of(context).pop();
}
},
initialSelection: _selectImpl,
dropdownMenuEntries: const [
DropdownMenuEntry(value: "local", label: "本地存储"),
DropdownMenuEntry(value: "webdav", label: "webdav")
],
),
TextField(
decoration: const InputDecoration(labelText: "名称"),
controller: nameController,
),
_selectImpl == "local"
? TextField(
decoration: const InputDecoration(labelText: "路径"),
controller: pathController,
)
: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: "Webdav网址"),
controller: urlController,
),
TextField(
decoration:
const InputDecoration(labelText: "用户"),
controller: userController,
),
TextField(
decoration:
const InputDecoration(labelText: "密码"),
controller: passController,
),
TextField(
decoration:
const InputDecoration(labelText: "路径"),
controller: pathController,
),
],
)
],
),
),
],
);
actions: <Widget>[
s.id == null
? const Text("")
: TextButton(
onPressed: () {
var f = ref
.read(storageSettingProvider.notifier)
.deleteStorage(s.id!);
setState(() {
_pendingStorage = f;
});
if (!showError(snapshot)) {
Navigator.of(context).pop();
}
},
child: const Text('删除')),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消')),
TextButton(
child: const Text('确定'),
onPressed: () async {
ref
.read(storageSettingProvider.notifier)
.addStorage(Storage(
name: nameController.text,
implementation: _selectImpl,
settings: {
"path": pathController.text,
"url": urlController.text,
"user": userController.text,
"password": passController.text
},
));
if (!showError(snapshot)) {
Navigator.of(context).pop();
}
},
),
],
);
});
});
}