Skip to content

Commit 85cb14e

Browse files
committed
feat: Android 扩展导入
1 parent 4ab1331 commit 85cb14e

File tree

5 files changed

+282
-78
lines changed

5 files changed

+282
-78
lines changed

lib/pages/extension/view.dart

Lines changed: 118 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
import 'dart:io';
2+
13
import 'package:fluent_ui/fluent_ui.dart' as fluent;
24
import 'package:flutter/material.dart';
5+
import 'package:flutter/services.dart';
36
import 'package:get/get.dart';
47
import 'package:miru_app/main.dart';
58
import 'package:miru_app/pages/extension/controller.dart';
69
import 'package:miru_app/pages/extension/widgets/extension_tile.dart';
710
import 'package:miru_app/pages/extension_repo/view.dart';
811
import 'package:miru_app/utils/extension.dart';
12+
import 'package:miru_app/utils/router.dart';
13+
import 'package:miru_app/widgets/button.dart';
14+
import 'package:miru_app/widgets/messenger.dart';
915
import 'package:miru_app/widgets/platform_widget.dart';
1016
import 'package:url_launcher/url_launcher.dart';
1117

@@ -28,90 +34,121 @@ class _ExtensionPageState extends State<ExtensionPage> {
2834
// 导入扩展对话框
2935
_importDialog() {
3036
String url = '';
31-
fluent.showDialog(
37+
showPlatformDialog(
3238
context: context,
33-
builder: (context) => fluent.ContentDialog(
34-
title: const Text("导入扩展"),
35-
content: Column(
36-
mainAxisSize: MainAxisSize.min,
37-
crossAxisAlignment: CrossAxisAlignment.start,
38-
children: [
39-
fluent.TextBox(
40-
placeholder: "扩展地址",
39+
title: "导入扩展",
40+
content: Column(
41+
mainAxisSize: MainAxisSize.min,
42+
crossAxisAlignment: CrossAxisAlignment.start,
43+
children: [
44+
PlatformWidget(
45+
androidWidget: TextField(
46+
decoration: const InputDecoration(
47+
labelText: "扩展地址",
48+
hintText: "https://example.com/extension.js",
49+
),
4150
onChanged: (value) {
4251
url = value;
4352
},
4453
),
45-
const SizedBox(height: 16),
46-
const Row(
47-
children: [
48-
Icon(fluent.FluentIcons.error),
49-
SizedBox(width: 8),
50-
Text(
51-
"你可以通过链接导入扩展,\n或者点击下方的扩展目录,将扩展文件\n放入其中。",
52-
softWrap: true,
53-
)
54-
],
54+
desktopWidget: fluent.TextBox(
55+
placeholder: "扩展地址",
56+
onChanged: (value) {
57+
url = value;
58+
},
5559
),
56-
],
57-
),
58-
actions: [
59-
fluent.Button(
60-
onPressed: () {
61-
router.pop();
62-
},
63-
child: const Text("取消"),
6460
),
65-
fluent.FilledButton(
66-
onPressed: () async {
67-
router.pop();
68-
// 定位目录
69-
final dir = await ExtensionUtils.getExtensionsDir;
70-
final uri = Uri.directory(dir);
71-
await launchUrl(uri);
72-
},
73-
child: const Text("扩展目录"),
74-
),
75-
fluent.FilledButton(
76-
onPressed: () async {
77-
Navigator.of(context).pop();
78-
await ExtensionUtils.install(url, context);
79-
},
80-
child: const Text("通过链接导入"),
61+
const SizedBox(height: 16),
62+
const Row(
63+
children: [
64+
Icon(fluent.FluentIcons.error),
65+
SizedBox(width: 8),
66+
Text(
67+
"你可以通过链接导入扩展,\n或者点击下方的扩展目录,将扩展文件\n放入其中。",
68+
softWrap: true,
69+
)
70+
],
8171
),
8272
],
8373
),
74+
actions: [
75+
PlatformButton(
76+
onPressed: () {
77+
RouterUtils.pop();
78+
},
79+
child: const Text("取消"),
80+
),
81+
PlatformFilledButton(
82+
onPressed: () async {
83+
RouterUtils.pop();
84+
// 定位目录
85+
final dir = await ExtensionUtils.getExtensionsDir;
86+
if (Platform.isAndroid) {
87+
// 复制 dir
88+
Clipboard.setData(ClipboardData(text: dir));
89+
// ignore: use_build_context_synchronously
90+
showPlatformSnackbar(
91+
context: context,
92+
title: '扩展目录',
93+
content: '已复制到剪贴板',
94+
);
95+
return;
96+
}
97+
final uri = Uri.directory(dir);
98+
await launchUrl(uri);
99+
},
100+
child: const Text("扩展目录"),
101+
),
102+
PlatformFilledButton(
103+
onPressed: () async {
104+
RouterUtils.pop();
105+
await ExtensionUtils.install(url, context);
106+
},
107+
child: const Text("通过链接导入"),
108+
),
109+
],
84110
);
85111
}
86112

87113
// 加载错误对话框
88114
_loadErrorDialog() {
89-
fluent.showDialog(
115+
showPlatformDialog(
90116
context: context,
91-
builder: (context) => fluent.ContentDialog(
92-
title: const Text("错误信息"),
93-
content: ListView(
94-
shrinkWrap: true,
117+
title: "错误信息",
118+
content: SingleChildScrollView(
119+
child: Column(
120+
mainAxisSize: MainAxisSize.min,
95121
children: [
96122
// 输出key 和 value
97123
for (final e in c.errors.entries)
98-
fluent.Card(
99-
margin: const EdgeInsets.only(bottom: 8),
100-
child: Text(
101-
"${e.key}: ${e.value}",
124+
PlatformWidget(
125+
androidWidget: Card(
126+
margin: const EdgeInsets.only(bottom: 8),
127+
child: Container(
128+
padding: const EdgeInsets.all(16),
129+
child: Text(
130+
"${e.key}: ${e.value}",
131+
),
132+
),
133+
),
134+
desktopWidget: fluent.Card(
135+
margin: const EdgeInsets.only(bottom: 8),
136+
child: Text(
137+
"${e.key}: ${e.value}",
138+
),
102139
),
103140
),
104141
],
105142
),
106-
actions: [
107-
fluent.Button(
108-
onPressed: () {
109-
router.pop();
110-
},
111-
child: const Text("确定"),
112-
),
113-
],
114143
),
144+
actions: [
145+
PlatformButton(
146+
onPressed: () {
147+
RouterUtils.pop();
148+
},
149+
child: const Text("确定"),
150+
),
151+
],
115152
);
116153
}
117154

@@ -122,10 +159,27 @@ class _ExtensionPageState extends State<ExtensionPage> {
122159
child: Scaffold(
123160
appBar: AppBar(
124161
title: const Text("扩展"),
125-
bottom: const TabBar(tabs: [
126-
Tab(text: "已安装"),
127-
Tab(text: "仓库"),
128-
]),
162+
bottom: const TabBar(
163+
tabs: [
164+
Tab(text: "已安装"),
165+
Tab(text: "仓库"),
166+
],
167+
),
168+
actions: [
169+
if (c.errors.isNotEmpty)
170+
IconButton(
171+
icon: const Icon(Icons.error),
172+
onPressed: () {
173+
_loadErrorDialog();
174+
},
175+
),
176+
],
177+
),
178+
floatingActionButton: FloatingActionButton(
179+
onPressed: () {
180+
_importDialog();
181+
},
182+
child: const Icon(Icons.add),
129183
),
130184
body: TabBarView(children: [
131185
ListView(

lib/utils/extension.dart

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import 'package:desktop_multi_window/desktop_multi_window.dart';
55
import 'package:dio/dio.dart';
66
import 'package:fluent_ui/fluent_ui.dart';
77
import 'package:get/get.dart';
8-
import 'package:miru_app/main.dart';
98
import 'package:miru_app/models/extension.dart';
109
import 'package:miru_app/pages/extension/controller.dart';
1110
import 'package:miru_app/pages/search/controller.dart';
1211
import 'package:miru_app/pages/settings/controller.dart';
1312
import 'package:miru_app/utils/extension_runtime.dart';
1413
import 'package:miru_app/utils/miru_directory.dart';
14+
import 'package:miru_app/utils/router.dart';
15+
import 'package:miru_app/widgets/button.dart';
16+
import 'package:miru_app/widgets/messenger.dart';
1517
import 'package:path/path.dart' as path;
1618

1719
class ExtensionUtils {
@@ -86,20 +88,18 @@ class ExtensionUtils {
8688
// 保存文件
8789
File(savePath).writeAsStringSync(res.data!);
8890
} catch (e) {
89-
showDialog(
91+
showPlatformDialog(
9092
context: context,
91-
builder: (context) => ContentDialog(
92-
title: const Text("安装错误"),
93-
content: Text(e.toString()),
94-
actions: [
95-
Button(
96-
child: const Text("关闭"),
97-
onPressed: () {
98-
router.pop();
99-
},
100-
)
101-
],
102-
),
93+
title: "安装错误",
94+
content: Text(e.toString()),
95+
actions: [
96+
PlatformButton(
97+
child: const Text("关闭"),
98+
onPressed: () {
99+
RouterUtils.pop();
100+
},
101+
)
102+
],
103103
);
104104
rethrow;
105105
}

lib/utils/router.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'dart:io';
2+
3+
import 'package:get/get.dart';
4+
import 'package:miru_app/main.dart';
5+
6+
class RouterUtils {
7+
static pop() {
8+
if (Platform.isAndroid) {
9+
return Get.back();
10+
}
11+
return router.pop();
12+
}
13+
}

lib/widgets/button.dart

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import 'package:fluent_ui/fluent_ui.dart' as fluent;
2+
import 'package:flutter/material.dart';
3+
import 'package:miru_app/widgets/platform_widget.dart';
4+
5+
class PlatformButton extends StatelessWidget {
6+
const PlatformButton({
7+
Key? key,
8+
required this.child,
9+
this.onPressed,
10+
}) : super(key: key);
11+
final Widget child;
12+
final VoidCallback? onPressed;
13+
14+
Widget _builaAndroidButton(BuildContext context) {
15+
return ElevatedButton(onPressed: onPressed, child: child);
16+
}
17+
18+
Widget _builaDesktopButton(BuildContext context) {
19+
return fluent.Button(onPressed: onPressed, child: child);
20+
}
21+
22+
@override
23+
Widget build(BuildContext context) {
24+
return PlatformBuildWidget(
25+
androidBuilder: _builaAndroidButton,
26+
desktopBuilder: _builaDesktopButton,
27+
);
28+
}
29+
}
30+
31+
class PlatformFilledButton extends StatelessWidget {
32+
const PlatformFilledButton({
33+
Key? key,
34+
required this.child,
35+
this.onPressed,
36+
}) : super(key: key);
37+
final Widget child;
38+
final VoidCallback? onPressed;
39+
40+
Widget _builaAndroidButton(BuildContext context) {
41+
return FilledButton(onPressed: onPressed, child: child);
42+
}
43+
44+
Widget _builaDesktopButton(BuildContext context) {
45+
return fluent.FilledButton(onPressed: onPressed, child: child);
46+
}
47+
48+
@override
49+
Widget build(BuildContext context) {
50+
return PlatformBuildWidget(
51+
androidBuilder: _builaAndroidButton,
52+
desktopBuilder: _builaDesktopButton,
53+
);
54+
}
55+
}
56+
57+
class PlatformTextButton extends StatelessWidget {
58+
const PlatformTextButton({
59+
Key? key,
60+
required this.child,
61+
this.onPressed,
62+
}) : super(key: key);
63+
final Widget child;
64+
final VoidCallback? onPressed;
65+
66+
Widget _builaAndroidButton(BuildContext context) {
67+
return TextButton(onPressed: onPressed, child: child);
68+
}
69+
70+
Widget _builaDesktopButton(BuildContext context) {
71+
return fluent.HyperlinkButton(onPressed: onPressed, child: child);
72+
}
73+
74+
@override
75+
Widget build(BuildContext context) {
76+
return PlatformBuildWidget(
77+
androidBuilder: _builaAndroidButton,
78+
desktopBuilder: _builaDesktopButton,
79+
);
80+
}
81+
}

0 commit comments

Comments
 (0)