mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new: wear settings (#358) & opt.: android widget edit
This commit is contained in:
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -11,22 +11,32 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
releaseAL:
|
releaseAL:
|
||||||
name: Release android and linux
|
name: Release android and linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: '0'
|
||||||
- name: Install Flutter
|
- name: Install Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: '17'
|
||||||
|
- name: Fetch secrets
|
||||||
|
run: |
|
||||||
|
curl -u ${{ secrets.BASIC_AUTH }} -o android/app/app.key ${{ secrets.URL_PREFIX }}app.key
|
||||||
|
curl -u ${{ secrets.BASIC_AUTH }} -o android/key.properties ${{ secrets.URL_PREFIX }}key.properties
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dart run fl_build -p android,linux
|
run: dart run fl_build -p android,linux
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_arm64.apk
|
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_arm64.apk
|
||||||
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_arm.apk
|
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_arm.apk
|
||||||
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_amd64.apk
|
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_amd64.apk
|
||||||
${{ env.APP_NAME }}_amd64.AppImage
|
${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_amd64.AppImage
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:fl_lib/l10n/gen/lib_l10n.dart';
|
import 'package:fl_lib/l10n/gen_l10n/lib_l10n.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:toolbox/data/res/build_data.dart';
|
import 'package:toolbox/data/res/build_data.dart';
|
||||||
|
|||||||
@@ -246,4 +246,8 @@ class AppRoutes {
|
|||||||
static AppRoutes pve({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes pve({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoutes(PvePage(key: key, spi: spi), 'pve');
|
return AppRoutes(PvePage(key: key, spi: spi), 'pve');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AppRoutes kvEditor({Key? key, required Map<String, String> data}) {
|
||||||
|
return AppRoutes(KvEditor(key: key, data: data), 'kv_editor');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ final class WearHome extends StatefulWidget {
|
|||||||
const WearHome({super.key});
|
const WearHome({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_WearHomeState createState() => _WearHomeState();
|
State<WearHome> createState() => _WearHomeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
final class _WearHomeState extends State<WearHome> with AfterLayoutMixin {
|
final class _WearHomeState extends State<WearHome> with AfterLayoutMixin {
|
||||||
@@ -61,11 +61,30 @@ final class _WearHomeState extends State<WearHome> with AfterLayoutMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEachSever(Server srv) {
|
Widget _buildEachSever(Server srv) {
|
||||||
return const Padding(
|
final mem = () {
|
||||||
padding: EdgeInsets.all(7),
|
final total = srv.status.mem.total;
|
||||||
|
final used = srv.status.mem.total - srv.status.mem.avail;
|
||||||
|
return '${used.bytes2Str} / ${total.bytes2Str}';
|
||||||
|
}();
|
||||||
|
final disk = () {
|
||||||
|
final total = srv.status.diskUsage?.size.kb2Str;
|
||||||
|
final used = srv.status.diskUsage?.used.kb2Str;
|
||||||
|
return '$used / $total';
|
||||||
|
}();
|
||||||
|
final net = '↓ ${srv.status.netSpeed.cachedRealVals.speedIn}'
|
||||||
|
'↑ ${srv.status.netSpeed.cachedRealVals.speedOut}';
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(7),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [],
|
children: [
|
||||||
|
Text(srv.spi.name, style: UIs.text15Bold),
|
||||||
|
UIs.height7,
|
||||||
|
KvRow(k: 'CPU', v: '${srv.status.cpu.usedPercent()}%'),
|
||||||
|
KvRow(k: 'Mem', v: mem),
|
||||||
|
KvRow(k: 'Disk', v: disk),
|
||||||
|
KvRow(k: 'Net', v: net)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1163,19 +1163,29 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
leading: const Icon(Icons.image),
|
leading: const Icon(Icons.image),
|
||||||
title: Text('Logo ${l10n.addr}'),
|
title: Text('Logo ${l10n.addr}'),
|
||||||
subtitle: SimpleMarkdown(data: '[${l10n.doc}](${Urls.appWiki})'),
|
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final ctrl =
|
final ctrl =
|
||||||
TextEditingController(text: _setting.serverLogoUrl.fetch());
|
TextEditingController(text: _setting.serverLogoUrl.fetch());
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: 'Logo ${l10n.addr}',
|
title: 'Logo ${l10n.addr}',
|
||||||
child: Input(
|
child: Column(
|
||||||
controller: ctrl,
|
mainAxisSize: MainAxisSize.min,
|
||||||
autoFocus: true,
|
children: [
|
||||||
hint: 'https://example.com/logo.png',
|
Input(
|
||||||
icon: Icons.link,
|
controller: ctrl,
|
||||||
onSubmitted: onSave,
|
autoFocus: true,
|
||||||
|
hint: 'https://example.com/logo.png',
|
||||||
|
icon: Icons.link,
|
||||||
|
maxLines: 3,
|
||||||
|
onSubmitted: onSave,
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(l10n.doc),
|
||||||
|
trailing: const Icon(Icons.open_in_new),
|
||||||
|
onTap: () => Urls.appWiki.launch(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
|
import 'package:toolbox/core/route.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:toolbox/view/page/setting/platform/platform_pub.dart';
|
import 'package:toolbox/view/page/setting/platform/platform_pub.dart';
|
||||||
|
import 'package:watch_connectivity/watch_connectivity.dart';
|
||||||
|
|
||||||
class AndroidSettingsPage extends StatefulWidget {
|
class AndroidSettingsPage extends StatefulWidget {
|
||||||
const AndroidSettingsPage({super.key});
|
const AndroidSettingsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AndroidSettingsPageState createState() => _AndroidSettingsPageState();
|
State<AndroidSettingsPage> createState() => _AndroidSettingsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
||||||
late SharedPreferences _sp;
|
late SharedPreferences _sp;
|
||||||
|
final wc = WatchConnectivity();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -34,6 +35,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
|||||||
children: [
|
children: [
|
||||||
_buildBgRun(),
|
_buildBgRun(),
|
||||||
_buildAndroidWidgetSharedPreference(),
|
_buildAndroidWidgetSharedPreference(),
|
||||||
|
_buildWatch(),
|
||||||
if (BioAuth.isPlatformSupported)
|
if (BioAuth.isPlatformSupported)
|
||||||
PlatformPublicSettings.buildBioAuth(),
|
PlatformPublicSettings.buildBioAuth(),
|
||||||
].map((e) => CardX(child: e)).toList(),
|
].map((e) => CardX(child: e)).toList(),
|
||||||
@@ -49,10 +51,9 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _saveWidgetSP(String data, Map<String, String> old) {
|
void _saveWidgetSP(Map<String, String> map, Map<String, String> old) {
|
||||||
context.pop();
|
context.pop();
|
||||||
try {
|
try {
|
||||||
final map = Map<String, String>.from(json.decode(data));
|
|
||||||
final keysDel = old.keys.toSet().difference(map.keys.toSet());
|
final keysDel = old.keys.toSet().difference(map.keys.toSet());
|
||||||
for (final key in keysDel) {
|
for (final key in keysDel) {
|
||||||
_sp.remove(key);
|
_sp.remove(key);
|
||||||
@@ -70,7 +71,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.homeWidgetUrlConfig),
|
title: Text(l10n.homeWidgetUrlConfig),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
final data = <String, String>{};
|
final data = <String, String>{};
|
||||||
_sp.getKeys().forEach((key) {
|
_sp.getKeys().forEach((key) {
|
||||||
final val = _sp.getString(key);
|
final val = _sp.getString(key);
|
||||||
@@ -78,25 +79,57 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
|||||||
data[key] = val;
|
data[key] = val;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
final ctrl = TextEditingController(text: json.encode(data));
|
final result = await AppRoutes.kvEditor(data: data).go(context);
|
||||||
context.showRoundDialog(
|
if (result != null) {
|
||||||
title: l10n.homeWidgetUrlConfig,
|
if (result is Map<String, String>) {
|
||||||
child: Input(
|
_saveWidgetSP(result, data);
|
||||||
autoFocus: true,
|
} else {
|
||||||
controller: ctrl,
|
final err = 'Save Android widget SharedPreference failed: '
|
||||||
label: 'JSON',
|
'unexpected type: ${result.runtimeType}';
|
||||||
type: TextInputType.visiblePassword,
|
Loggers.app.warning(err);
|
||||||
maxLines: 7,
|
context.showRoundDialog(
|
||||||
onSubmitted: (p0) => _saveWidgetSP(p0, data),
|
title: l10n.error,
|
||||||
),
|
child: SingleChildScrollView(
|
||||||
actions: [
|
child: SimpleMarkdown(data: '$err\n\n```$result```'),
|
||||||
TextButton(
|
),
|
||||||
onPressed: () {
|
);
|
||||||
_saveWidgetSP(ctrl.text, data);
|
}
|
||||||
},
|
}
|
||||||
child: Text(l10n.ok),
|
},
|
||||||
),
|
);
|
||||||
],
|
}
|
||||||
|
|
||||||
|
Widget _buildWatch() {
|
||||||
|
return FutureWidget(
|
||||||
|
future: wc.isReachable,
|
||||||
|
error: (e, s) {
|
||||||
|
Loggers.app.warning('WatchOS error', e, s);
|
||||||
|
return ListTile(
|
||||||
|
title: const Text('Watch app'),
|
||||||
|
subtitle: Text(l10n.viewErr, style: UIs.textGrey),
|
||||||
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
|
onTap: () {
|
||||||
|
context.showRoundDialog(
|
||||||
|
title: l10n.error,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: SimpleMarkdown(data: '${e.toString()}\n```$s```'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
success: (val) {
|
||||||
|
if (val == null) {
|
||||||
|
return ListTile(
|
||||||
|
title: const Text('Watch app'),
|
||||||
|
subtitle: Text(l10n.watchNotPaired, style: UIs.textGrey),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ListTile(
|
||||||
|
title: const Text('Watch app'),
|
||||||
|
subtitle: Text(l10n.sync, style: UIs.textGrey),
|
||||||
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
|
onTap: () async {},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ packages:
|
|||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: a2aa5359253ad83000ff2612ed2c5729cb0dcfc5
|
resolved-ref: "4a3ac8cec9b39a08790101e45ff80a42c6dfd36a"
|
||||||
url: "https://github.com/lollipopkit/fl_lib"
|
url: "https://github.com/lollipopkit/fl_lib"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user