WIP: init wizard

This commit is contained in:
Simon Ding
2024-11-10 13:28:21 +08:00
parent a83f860624
commit aaa006a322
3 changed files with 287 additions and 83 deletions

190
ui/lib/init_wizard.dart Normal file
View File

@@ -0,0 +1,190 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:ui/settings/prowlarr.dart';
import 'package:ui/widgets/widgets.dart';
class InitWizard extends ConsumerStatefulWidget {
const InitWizard({super.key});
static final String route = "/init_wizard";
@override
ConsumerState<ConsumerStatefulWidget> createState() {
return _InitWizardState();
}
}
class _InitWizardState extends ConsumerState<InitWizard> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SelectionArea(
child: Container(
padding: EdgeInsets.all(50),
child: ListView(
children: [
Container(
alignment: Alignment.center,
child: Text(
"Polaris 影视追踪下载",
style: TextStyle(
fontSize: 30,
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold),
),
),
Container(
padding: EdgeInsets.only(left: 10, top: 30, bottom: 30),
child: Text(
"设置向导",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary),
),
),
tmdbSetting(),
downloaderSetting(),
indexerSetting(),
],
),
)),
);
}
Widget tmdbSetting() {
return ExpansionTile(
title: Text(
"第一步TMDB设置",
style: TextStyle(fontWeight: FontWeight.bold),
),
childrenPadding: EdgeInsets.only(left: 100, right: 20),
initiallyExpanded: true,
children: [
Container(
alignment: Alignment.topLeft,
child: Text("TMDB API Key 设置用来获取各种影视的信息API Key获取方式参考官网"),
),
FormBuilder(
child: Column(
children: [
FormBuilderTextField(
name: "tmdb",
decoration: InputDecoration(labelText: "TMDB API Key"),
),
Center(
child: Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(onPressed: null, child: Text("保存")),
))
],
))
],
);
}
Widget indexerSetting() {
return ExpansionTile(
initiallyExpanded: true,
childrenPadding: EdgeInsets.only(left: 100, right: 20),
title: Text(
"第三步Prowlarr设置",
style: TextStyle(fontWeight: FontWeight.bold),
),
children: [ProwlarrSettingPage()],
);
}
Widget downloaderSetting() {
final _formKey = GlobalKey<FormBuilderState>();
var _enableAuth = false;
String selectImpl = "transmission";
return ExpansionTile(
childrenPadding: EdgeInsets.only(left: 100, right: 20),
initiallyExpanded: true,
title: Text("第二步:下载客户端", style: TextStyle(fontWeight: FontWeight.bold)),
children: [
StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
return FormBuilder(
key: _formKey,
initialValue: {
"name": "client.name",
"url": "client.url",
"user": "client.user",
"password": "client.password",
"impl": selectImpl,
},
child: Column(
children: [
FormBuilderDropdown<String>(
name: "impl",
decoration: const InputDecoration(labelText: "类型"),
items: const [
DropdownMenuItem(
value: "transmission", child: Text("Transmission")),
DropdownMenuItem(
value: "qbittorrent", child: Text("qBittorrent")),
],
validator: FormBuilderValidators.required(),
),
FormBuilderTextField(
name: "name",
decoration: const InputDecoration(labelText: "名称"),
validator: FormBuilderValidators.required(),
autovalidateMode: AutovalidateMode.onUserInteraction),
FormBuilderTextField(
name: "url",
decoration: const InputDecoration(
labelText: "地址", hintText: "http://127.0.0.1:9091"),
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: FormBuilderValidators.required(),
),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
children: [
FormBuilderSwitch(
name: "auth",
title: const Text("需要认证"),
initialValue: _enableAuth,
onChanged: (v) {
setState(() {
_enableAuth = v!;
});
}),
_enableAuth
? Column(
children: [
FormBuilderTextField(
name: "user",
decoration:
Commons.requiredTextFieldStyle(
text: "用户"),
validator:
FormBuilderValidators.required(),
autovalidateMode:
AutovalidateMode.onUserInteraction),
FormBuilderTextField(
name: "password",
decoration:
Commons.requiredTextFieldStyle(
text: "密码"),
validator:
FormBuilderValidators.required(),
obscureText: true,
autovalidateMode:
AutovalidateMode.onUserInteraction),
],
)
: Container()
],
);
})
],
));
}),
],
);
}
}

View File

@@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
import 'package:ui/activity.dart'; import 'package:ui/activity.dart';
import 'package:ui/calendar.dart'; import 'package:ui/calendar.dart';
import 'package:ui/init_wizard.dart';
import 'package:ui/login_page.dart'; import 'package:ui/login_page.dart';
import 'package:ui/movie_watchlist.dart'; import 'package:ui/movie_watchlist.dart';
import 'package:ui/providers/APIs.dart'; import 'package:ui/providers/APIs.dart';
@@ -124,9 +125,17 @@ class _MyAppState extends ConsumerState<MyApp> {
initialLocation: WelcomePage.routeTv, initialLocation: WelcomePage.routeTv,
routes: [ routes: [
shellRoute, shellRoute,
GoRoute(
path: "/",
redirect: (context, state) => WelcomePage.routeTv,
),
GoRoute( GoRoute(
path: LoginScreen.route, path: LoginScreen.route,
builder: (context, state) => const LoginScreen(), builder: (context, state) => const LoginScreen(),
),
GoRoute(
path: InitWizard.route,
builder: (context, state) => const InitWizard(),
) )
], ],
); );
@@ -171,7 +180,71 @@ class _MainSkeletonState extends State<MainSkeleton> {
var padding = isSmallScreen(context) ? 5.0 : 20.0; var padding = isSmallScreen(context) ? 5.0 : 20.0;
return AdaptiveScaffold( return AdaptiveScaffold(
appBarBreakpoint: Breakpoints.standard, appBarBreakpoint: Breakpoints.standard,
appBar: AppBar( appBar: appBar(),
useDrawer: false,
selectedIndex: widget.body.currentIndex,
onSelectedIndexChange: (p0) => widget.body
.goBranch(p0, initialLocation: p0 == widget.body.currentIndex),
destinations: const <NavigationDestination>[
NavigationDestination(
icon: Icon(Icons.live_tv_outlined),
selectedIcon: Icon(Icons.live_tv),
label: '剧集',
),
NavigationDestination(
icon: Icon(Icons.movie_outlined),
selectedIcon: Icon(Icons.movie),
label: '电影',
),
NavigationDestination(
icon: Icon(Icons.download_outlined),
selectedIcon: Icon(Icons.download),
label: '活动',
),
NavigationDestination(
icon: Icon(Icons.settings_outlined),
selectedIcon: Icon(Icons.settings),
label: '设置',
),
NavigationDestination(
icon: Icon(Icons.computer_outlined),
selectedIcon: Icon(Icons.computer),
label: '系统',
),
],
body: (context) => SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: padding, right: padding, top: 5, bottom: 5),
child: widget.body)),
// Define a default secondaryBody.
// Override the default secondaryBody during the smallBreakpoint to be
// empty. Must use AdaptiveScaffold.emptyBuilder to ensure it is properly
// overridden.
);
}
showDonate(BuildContext context) {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: Text("项目开发不易,给开发者加个鸡腿:"),
content: SizedBox(
width: 350,
height: 400,
child: Ink.image(
fit: BoxFit.fitWidth,
image: AssetImage("assets/wechat.jpg"))),
);
},
);
}
AppBar appBar() {
return AppBar(
// TRY THIS: Try changing the color here to a specific color (to // TRY THIS: Try changing the color here to a specific color (to
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
// change color while the other colors stay the same. // change color while the other colors stay the same.
@@ -252,66 +325,6 @@ class _MainSkeletonState extends State<MainSkeleton> {
}, },
), ),
], ],
),
useDrawer: false,
selectedIndex: widget.body.currentIndex,
onSelectedIndexChange: (p0) => widget.body
.goBranch(p0, initialLocation: p0 == widget.body.currentIndex),
destinations: const <NavigationDestination>[
NavigationDestination(
icon: Icon(Icons.live_tv_outlined),
selectedIcon: Icon(Icons.live_tv),
label: '剧集',
),
NavigationDestination(
icon: Icon(Icons.movie_outlined),
selectedIcon: Icon(Icons.movie),
label: '电影',
),
NavigationDestination(
icon: Icon(Icons.download_outlined),
selectedIcon: Icon(Icons.download),
label: '活动',
),
NavigationDestination(
icon: Icon(Icons.settings_outlined),
selectedIcon: Icon(Icons.settings),
label: '设置',
),
NavigationDestination(
icon: Icon(Icons.computer_outlined),
selectedIcon: Icon(Icons.computer),
label: '系统',
),
],
body: (context) => SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: padding, right: padding, top: 5, bottom: 5),
child: widget.body)),
// Define a default secondaryBody.
// Override the default secondaryBody during the smallBreakpoint to be
// empty. Must use AdaptiveScaffold.emptyBuilder to ensure it is properly
// overridden.
);
}
showDonate(BuildContext context) {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: Text("项目开发不易,给开发者加个鸡腿:"),
content: SizedBox(
width: 350,
height: 400,
child: Ink.image(
fit: BoxFit.fitWidth,
image: AssetImage("assets/wechat.jpg"))),
);
},
); );
} }
} }

View File

@@ -51,7 +51,8 @@ class ProwlarrSettingState extends ConsumerState<ProwlarrSettingPage> {
FormBuilderSwitch( FormBuilderSwitch(
name: "disabled", name: "disabled",
title: const Text("禁用 Prowlarr"), title: const Text("禁用 Prowlarr"),
decoration: InputDecoration(icon: Icon(Icons.do_not_disturb)), decoration:
InputDecoration(icon: Icon(Icons.do_not_disturb)),
), ),
Center( Center(
child: Padding( child: Padding(