opt. for docker & apt

This commit is contained in:
lollipopkit
2022-12-10 23:14:55 +08:00
parent 62a1122174
commit 611518f790
22 changed files with 686 additions and 213 deletions

View File

@@ -58,61 +58,60 @@ class _AptManagePageState extends State<AptManagePage>
return;
}
// ignore: prefer_function_declarations_over_variables
Function onSubmitted = () {
if (textController.text == '') {
showRoundDialog(context, s.attention, Text(s.fieldMustNotEmpty), [
TextButton(
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok)),
]);
return;
}
Navigator.of(context).pop();
};
// ignore: prefer_function_declarations_over_variables
PwdRequestFunc onPwdRequest = (triedTimes, user) async {
if (!mounted) return '';
await showRoundDialog(
context,
triedTimes == 3 ? s.lastTry : (user ?? s.unknown),
TextField(
controller: textController,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
onSubmitted: (_) => onSubmitted(),
decoration: InputDecoration(
labelText: s.pwd,
),
),
[
TextButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
child: Text(s.cancel)),
TextButton(
onPressed: () => onSubmitted(),
child: Text(
s.ok,
style: const TextStyle(color: Colors.red),
)),
]);
return textController.text.trim();
};
_aptProvider.init(
si.client!,
si.status.sysVer.dist,
() =>
scrollController.jumpTo(scrollController.position.maxScrollExtent),
() => scrollControllerUpdate
.jumpTo(scrollControllerUpdate.positions.last.maxScrollExtent),
onPwdRequest);
.jumpTo(scrollController.position.maxScrollExtent),
onPwdRequest,
widget.spi.user);
_aptProvider.refreshInstalled();
}
void onSubmitted() {
if (textController.text == '') {
showRoundDialog(context, s.attention, Text(s.fieldMustNotEmpty), [
TextButton(
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok)),
]);
return;
}
Navigator.of(context).pop();
}
Future<String> onPwdRequest() async {
if (!mounted) return '';
await showRoundDialog(
context,
widget.spi.user,
TextField(
controller: textController,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
onSubmitted: (_) => onSubmitted(),
decoration: InputDecoration(
labelText: s.pwd,
),
),
[
TextButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
child: Text(s.cancel)),
TextButton(
onPressed: () => onSubmitted(),
child: Text(
s.ok,
style: const TextStyle(color: Colors.red),
)),
]);
return textController.text.trim();
}
@override
Widget build(BuildContext context) {
return Scaffold(

View File

@@ -6,7 +6,9 @@ import 'package:toolbox/data/model/docker/ps.dart';
import 'package:toolbox/data/model/server/server_private_info.dart';
import 'package:toolbox/data/provider/docker.dart';
import 'package:toolbox/data/provider/server.dart';
import 'package:toolbox/data/res/error.dart';
import 'package:toolbox/data/res/url.dart';
import 'package:toolbox/data/store/docker.dart';
import 'package:toolbox/generated/l10n.dart';
import 'package:toolbox/locator.dart';
import 'package:toolbox/view/widget/center_loading.dart';
@@ -25,6 +27,7 @@ class DockerManagePage extends StatefulWidget {
class _DockerManagePageState extends State<DockerManagePage> {
final _docker = locator<DockerProvider>();
final greyTextStyle = const TextStyle(color: Colors.grey);
final textController = TextEditingController();
late S s;
@override
@@ -51,69 +54,233 @@ class _DockerManagePageState extends State<DockerManagePage> {
Navigator.of(context).pop();
return;
}
_docker.init(client, widget.spi.user);
_docker.init(client, widget.spi.user, onPwdRequest, widget.spi.id);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: TwoLineText(up: 'Docker', down: widget.spi.name),
),
body: _buildMain(),
);
}
Widget _buildMain() {
return Consumer<DockerProvider>(builder: (_, docker, __) {
final running = docker.items;
if (docker.error != null && running == null) {
return SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.error,
size: 37,
),
const SizedBox(height: 27),
Text(docker.error!),
const SizedBox(height: 27),
Padding(
padding: const EdgeInsets.all(17),
child: _buildSolution(docker.error!),
)
],
),
);
}
if (running == null) {
_docker.refresh();
return centerLoading;
}
return ListView(
padding: const EdgeInsets.all(7),
children: [
_buildVersion(
docker.edition ?? s.unknown, docker.version ?? s.unknown),
_buildPsItems(running, docker)
].map((e) => RoundRectCard(e)).toList(),
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: TwoLineText(up: 'Docker', down: widget.spi.name),
actions: [
IconButton(
onPressed: () => docker.refresh(),
icon: const Icon(Icons.refresh))
],
),
body: _buildMain(docker),
floatingActionButton: _buildFAB(docker),
);
});
}
Widget _buildSolution(String err) {
switch (err) {
case 'docker not found':
Widget _buildFAB(DockerProvider docker) {
final c = TextEditingController();
return FloatingActionButton(
onPressed: () {
showRoundDialog(
context,
s.cmd,
TextField(
keyboardType: TextInputType.multiline,
maxLines: 7,
controller: c,
autocorrect: false,
),
[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(s.cancel),
),
TextButton(
onPressed: () async {
Navigator.of(context).pop();
final result = await docker.run(c.text.trim());
if (result != null) {
showSnackBar(
context, Text(getErrMsg(result) ?? s.unknownError));
}
},
child: Text(s.run),
)
],
);
},
child: const Icon(Icons.code),
);
}
String? getErrMsg(DockerErr err) {
switch (err.type) {
case DockerErrType.cmdNoPrefix:
return s.dockerCmdPrefixErr;
default:
return null;
}
}
void onSubmitted() {
if (textController.text == '') {
showRoundDialog(context, s.attention, Text(s.fieldMustNotEmpty), [
TextButton(
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok)),
]);
return;
}
Navigator.of(context).pop();
}
Future<String> onPwdRequest() async {
if (!mounted) return '';
await showRoundDialog(
context,
widget.spi.user,
TextField(
controller: textController,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
onSubmitted: (_) => onSubmitted(),
decoration: InputDecoration(
labelText: s.pwd,
),
),
[
TextButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
child: Text(s.cancel)),
TextButton(
onPressed: () => onSubmitted(),
child: Text(
s.ok,
style: const TextStyle(color: Colors.red),
)),
]);
return textController.text.trim();
}
Widget _buildMain(DockerProvider docker) {
final running = docker.items;
if (docker.error != null && running == null) {
return SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.error,
size: 37,
),
const SizedBox(height: 27),
_buildErr(docker.error!),
const SizedBox(height: 27),
Padding(
padding: const EdgeInsets.all(17),
child: _buildSolution(docker.error!),
)
],
),
);
}
if (running == null) {
_docker.refresh();
return centerLoading;
}
return ListView(
padding: const EdgeInsets.all(7),
children: [
_buildVersion(docker.edition ?? s.unknown, docker.version ?? s.unknown),
_buildPsItems(running, docker),
_buildEditHost(running, docker),
_buildRunLog(docker),
].map((e) => RoundRectCard(e)).toList(),
);
}
Widget _buildRunLog(DockerProvider docker) {
if (docker.runLog == null) return const SizedBox();
return Padding(
padding: const EdgeInsets.all(17),
child: Text(docker.runLog!, maxLines: 1,),
);
}
Widget _buildEditHost(List<DockerPsItem> running, DockerProvider docker) {
if (running.isEmpty) {
return Padding(
padding: const EdgeInsets.fromLTRB(17, 17, 17, 0),
child: Column(
children: [
Text(
s.dockerEmptyRunningItems,
textAlign: TextAlign.center,
),
TextButton(
onPressed: () => _showEditHostDialog(docker),
child: Text(s.dockerEditHost))
],
),
);
}
return const SizedBox();
}
Future<void> _showEditHostDialog(DockerProvider docker) async {
await showRoundDialog(
context,
s.dockerEditHost,
TextField(
maxLines: 1,
autocorrect: false,
controller:
TextEditingController(text: 'unix:///run/user/1000/docker.sock'),
onSubmitted: (value) {
locator<DockerStore>().setDockerHost(widget.spi.id, value.trim());
docker.refresh();
Navigator.of(context).pop();
},
),
[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(s.cancel)),
],
);
}
Widget _buildErr(DockerErr err) {
var errStr = '';
switch (err.type) {
case DockerErrType.noClient:
errStr = s.noClient;
break;
case DockerErrType.notInstalled:
errStr = s.dockerNotInstalled;
break;
case DockerErrType.invalidVersion:
errStr = s.invalidVersion;
break;
default:
errStr = err.message ?? s.unknown;
}
return Text(errStr);
}
Widget _buildSolution(DockerErr err) {
switch (err.type) {
case DockerErrType.notInstalled:
return UrlText(
text: s.installDockerWithUrl,
replace: s.install,
);
case 'no client':
case DockerErrType.noClient:
return Text(s.waitConnection);
case 'invalid version':
case DockerErrType.invalidVersion:
return UrlText(
text: s.invalidVersionHelp(issueUrl),
replace: 'Github',

View File

@@ -51,7 +51,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
body: ListView(
padding: const EdgeInsets.all(13),
children: [
SizedBox(height: _media.size.height * 0.03),
SizedBox(height: _media.size.height * 0.01),
_buildLinuxIcon(si.status.sysVer),
SizedBox(height: _media.size.height * 0.03),
_buildUpTimeAndSys(si.status),