mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 08:35:46 +08:00
Update code to v1.0.14 (10)
This commit is contained in:
182
lib/main.dart
182
lib/main.dart
@@ -28,6 +28,8 @@ import 'package:clipboard/clipboard.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_pty/flutter_pty.dart';
|
||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:network_info_plus/network_info_plus.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
//import 'package:flutter/services.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -165,12 +167,36 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
const Divider(height: 2, indent: 8, endIndent: 8),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
const Text("你可以在当前所有同一网络下的设备(如:连接同一路由器的手机,电脑等)里使用小小电脑。\n\n将下面的链接复制到其他设备,在其他设备上把链接localhost字样改为当前设备的IP地址(可以通过快捷指令查看,格式类似192.168.x.x),然后使用浏览器打开链接即可。"),
|
||||
const Text("你可以在当前所有同一网络下的设备(如:连接同一WiFi的手机,电脑等)里使用小小电脑。\n\n点击下面的按钮分享链接到其他设备后使用浏览器打开即可。"),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: [
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("复制分享链接"), onPressed: () async {
|
||||
final String? ip = await NetworkInfo().getWifiIP();
|
||||
if (!context.mounted) return;
|
||||
if (ip == null) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("无法获取IP地址"))
|
||||
);
|
||||
return;
|
||||
}
|
||||
FlutterClipboard.copy((Util.getCurrentProp("vncUrl") as String).replaceFirst(RegExp.escape("localhost"), ip)).then((value) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("已复制分享链接"))
|
||||
);
|
||||
});
|
||||
}),
|
||||
]),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vncUrl"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "网页跳转地址"), onChanged: (value) async {
|
||||
await Util.setCurrentProp("vncUrl", value);
|
||||
}),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vncUri"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "vnc链接"), onChanged: (value) async {
|
||||
await Util.setCurrentProp("vncUri", value);
|
||||
}),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[1],
|
||||
@@ -282,6 +308,96 @@ class _SettingPageState extends State<SettingPage> {
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[2],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("显示设置"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
const Text("""AVNC可以带来获得更好的操控体验;
|
||||
如触摸板触控,双击弹出键盘,自动剪切板,画中画模式等等。这是一个实验性功能。"""),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: [
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("AVNC启动时分辨率设置"), onPressed: () async {
|
||||
String w = "1440";
|
||||
String h = "720";
|
||||
showDialog(context: context, builder: (context) {
|
||||
return AlertDialog(title: const Text("分辨率设置"), content: SingleChildScrollView(child: Column(children: [
|
||||
TextFormField(autovalidateMode: AutovalidateMode.onUserInteraction, initialValue: w, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "宽"), keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
return Util.validateBetween(value, 200, 7680, () {
|
||||
w = value!;
|
||||
});
|
||||
}
|
||||
),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
TextFormField(autovalidateMode: AutovalidateMode.onUserInteraction, initialValue: h, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "高"), keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
return Util.validateBetween(value, 200, 7680, () {
|
||||
h = value!;
|
||||
});
|
||||
}
|
||||
),
|
||||
])), actions: [
|
||||
TextButton(onPressed:() {
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("取消")),
|
||||
TextButton(onPressed:() async {
|
||||
Util.termWrite("""sed -i -E "s@(geometry)=.*@\\1=${w}x${h}@" /etc/tigervnc/vncserver-config-tmoe
|
||||
sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("${w}x${h}. 下次启动时生效"))
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("保存")),
|
||||
]);
|
||||
});
|
||||
}),
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("AVNC设置"), onPressed: () async {
|
||||
await D.avncChannel.invokeMethod("launchPrefsPage", {});
|
||||
}),
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("关于AVNC"), onPressed: () async {
|
||||
await D.avncChannel.invokeMethod("launchAboutPage", {});
|
||||
}),
|
||||
]),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
SwitchListTile(title: const Text("默认使用AVNC"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("useAvnc") as bool, onChanged:(value) {
|
||||
G.prefs.setBool("useAvnc", value);
|
||||
setState(() {});
|
||||
},),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
const Divider(height: 2, indent: 8, endIndent: 8),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
const Text("""高分辨率支持可以为大屏幕设备带来更高清的体验!
|
||||
|
||||
注意:
|
||||
选项开启后显示会变得很大,请在图形界面的左栏设置里手动调整缩放到一个你认为合适的值。
|
||||
如果使用AVNC,可以在上面设置一个更大的分辨率。
|
||||
|
||||
一些软件可能会存在显示问题,或者显示速度变慢。"""),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultHidpiOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "HiDPI环境变量"), readOnly: Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!),
|
||||
onTap: () {
|
||||
if (Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!)) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("观看十二次视频广告永久解锁><"))
|
||||
);
|
||||
}
|
||||
},
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultHidpiOpt", value);
|
||||
},
|
||||
),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
SwitchListTile(title: const Text("高分辨率支持"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("isHidpiEnabled") as bool, onChanged:(value) {
|
||||
G.prefs.setBool("isHidpiEnabled", value);
|
||||
setState(() {});
|
||||
},),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[3],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("相机推流"), subtitle: Text("实验性功能"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
@@ -377,7 +493,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SizedBox.fromSize(size: const Size.square(8))
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[3],
|
||||
isExpanded: _expandState[4],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("文件访问"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
@@ -394,7 +510,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[4],
|
||||
isExpanded: _expandState[5],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("virgl加速"), subtitle: Text("实验性功能"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
@@ -451,7 +567,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[5],
|
||||
isExpanded: _expandState[6],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("跨架构/跨系统支持"), subtitle: Text("实验性功能"),);
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
@@ -584,38 +700,6 @@ fi""");
|
||||
},),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[6],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("高分辨率支持"), subtitle: Text("实验性功能"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
const Text("""为更大的屏幕带来更高清的体验!
|
||||
|
||||
注意:
|
||||
选项开启后显示会变得很大,请在图形界面的左栏设置里手动调整缩放到一个你认为合适的值。
|
||||
|
||||
一些软件可能会存在显示问题,或者显示速度变慢。"""),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultHidpiOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "HiDPI环境变量"), readOnly: Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!),
|
||||
onTap: () {
|
||||
if (Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!)) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("观看十二次视频广告永久解锁><"))
|
||||
);
|
||||
}
|
||||
},
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultHidpiOpt", value);
|
||||
},
|
||||
),
|
||||
SizedBox.fromSize(size: const Size.square(8)),
|
||||
SwitchListTile(title: const Text("高分辨率支持"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("isHidpiEnabled") as bool, onChanged:(value) {
|
||||
G.prefs.setBool("isHidpiEnabled", value);
|
||||
setState(() {});
|
||||
},),
|
||||
SizedBox.fromSize(size: const Size.square(16)),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[7],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
@@ -1351,7 +1435,7 @@ class TerminalPage extends StatelessWidget {
|
||||
}, onScaleEnd: (details) async {
|
||||
await G.prefs.setDouble("termFontScale", G.termFontScale.value);
|
||||
}, child: ValueListenableBuilder(valueListenable: G.termFontScale, builder:(context, value, child) {
|
||||
return TerminalView(G.termPtys[G.currentContainer]!.terminal, textScaleFactor: G.termFontScale.value, keyboardType: TextInputType.multiline);
|
||||
return TerminalView(G.termPtys[G.currentContainer]!.terminal, textScaler: TextScaler.linear(G.termFontScale.value), keyboardType: TextInputType.multiline);
|
||||
},) )),
|
||||
ValueListenableBuilder(valueListenable: G.terminalPageChange, builder:(context, value, child) {
|
||||
return (Util.getGlobal("isTerminalCommandsEnabled") as bool)?Padding(padding: const EdgeInsets.all(8), child: Row(children: [AnimatedBuilder(
|
||||
@@ -1581,14 +1665,28 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
G.pageIndex.value = index;
|
||||
},
|
||||
),
|
||||
);}),
|
||||
);}
|
||||
),
|
||||
floatingActionButton: ValueListenableBuilder(valueListenable: G.pageIndex, builder:(context, value, child) {
|
||||
return Visibility(visible: isLoadingComplete && (value == 0),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () => Workflow.launchBrowser(),
|
||||
tooltip: "进入图形界面",
|
||||
child: SpeedDial(
|
||||
children: [SpeedDialChild(
|
||||
child: const Icon(Icons.laptop_outlined),
|
||||
label: "使用noVNC",
|
||||
onTap: () => Workflow.launchBrowser(),
|
||||
),SpeedDialChild(
|
||||
child: const Icon(Icons.screenshot_monitor_outlined),
|
||||
label: "使用AVNC",
|
||||
onTap: () => Workflow.launchAvnc(),
|
||||
)],
|
||||
activeChild: const Icon(Icons.close),
|
||||
child: const Icon(Icons.play_arrow),
|
||||
),
|
||||
)
|
||||
// FloatingActionButton(
|
||||
// onPressed: () => Workflow.launchBrowser(),
|
||||
// tooltip: "进入图形界面",
|
||||
// child: const Icon(Icons.play_arrow),
|
||||
// ),
|
||||
);
|
||||
}), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
|
||||
@@ -97,6 +97,7 @@ class Util {
|
||||
//bool virgl = false 下次启动是否启用virgl
|
||||
//bool wakelock = false 屏幕常亮
|
||||
//bool isHidpiEnabled = false 是否开启高分辨率
|
||||
//bool useAvnc = false 是否默认使用AVNC
|
||||
//String defaultHidpiOpt 默认HiDPI环境变量
|
||||
//? int bootstrapVersion: 启动包版本
|
||||
//String[] containersInfo: 所有容器信息(json)
|
||||
@@ -119,7 +120,7 @@ class Util {
|
||||
case "isTerminalCommandsEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "termMaxLines" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(4095);
|
||||
case "termFontScale" : return b ? G.prefs.getDouble(key)! : (value){G.prefs.setDouble(key, value); return value;}(1.0);
|
||||
case "vip" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(0);
|
||||
case "vip" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(1);
|
||||
case "isStickyKey" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
|
||||
case "reinstallBootstrap" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "getifaddrsBridge" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
@@ -129,6 +130,7 @@ class Util {
|
||||
case "virgl" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "wakelock" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "isHidpiEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "useAvnc" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "defaultFFmpegCommand" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("-hide_banner -an -max_delay 1000000 -r 30 -f android_camera -camera_index 0 -i 0:0 -vf scale=iw/2:-1 -rtsp_transport udp -f rtsp rtsp://127.0.0.1:8554/stream");
|
||||
case "defaultVirglCommand" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("--socket-path=\$CONTAINER_DIR/tmp/.virgl_test");
|
||||
case "defaultVirglOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GALLIUM_DRIVER=virpipe MESA_GL_VERSION_OVERRIDE=4.0");
|
||||
@@ -138,8 +140,28 @@ class Util {
|
||||
}
|
||||
}
|
||||
|
||||
// await G.prefs.setStringList("containersInfo", ["""{
|
||||
// "name":"Debian Bookworm",
|
||||
// "boot":"${D.boot}",
|
||||
// "vnc":"startnovnc &",
|
||||
// "vncUrl":"http://localhost:36082/vnc.html?host=localhost&port=36082&autoconnect=true&resize=remote&password=12345678",
|
||||
// "commands":${jsonEncode(D.commands)}
|
||||
// }"""]);
|
||||
// case "lastDate" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("1970-01-01");
|
||||
|
||||
static dynamic getCurrentProp(String key) {
|
||||
return jsonDecode(Util.getGlobal("containersInfo")[G.currentContainer])[key];
|
||||
dynamic m = jsonDecode(Util.getGlobal("containersInfo")[G.currentContainer]);
|
||||
if (m.containsKey(key)) {
|
||||
return m[key];
|
||||
}
|
||||
switch (key) {
|
||||
case "name" : return (value){addCurrentProp(key, value); return value;}("Debian Bookworm");
|
||||
case "boot" : return (value){addCurrentProp(key, value); return value;}(D.boot);
|
||||
case "vnc" : return (value){addCurrentProp(key, value); return value;}("startnovnc &");
|
||||
case "vncUrl" : return (value){addCurrentProp(key, value); return value;}("http://localhost:36082/vnc.html?host=localhost&port=36082&autoconnect=true&resize=remote&password=12345678");
|
||||
case "vncUri" : return (value){addCurrentProp(key, value); return value;}("vnc://127.0.0.1:5904?VncPassword=12345678&SecurityType=2");
|
||||
case "commands" : return (value){addCurrentProp(key, value); return value;}(jsonDecode(jsonEncode(D.commands)));
|
||||
}
|
||||
}
|
||||
|
||||
//用来设置name, boot, vnc, vncUrl等
|
||||
@@ -153,6 +175,17 @@ class Util {
|
||||
);
|
||||
}
|
||||
|
||||
//用来添加不存在的key等
|
||||
static Future<void> addCurrentProp(String key, dynamic value) async {
|
||||
await G.prefs.setStringList("containersInfo",
|
||||
Util.getGlobal("containersInfo")..setAll(G.currentContainer,
|
||||
[jsonEncode((jsonDecode(
|
||||
Util.getGlobal("containersInfo")[G.currentContainer]
|
||||
))..addAll({key : value}))]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//返回单个G.bonusTable定义的item
|
||||
static Map<String, dynamic> getRandomBonus() {
|
||||
final random = Random();
|
||||
@@ -365,16 +398,20 @@ class D {
|
||||
{"name":"卸载Kdenlive", "command":"sudo apt autoremove --purge -y kdenlive"},
|
||||
{"name":"安装科学计算软件Octave", "command":"sudo apt update && sudo apt install -y octave"},
|
||||
{"name":"卸载Octave", "command":"sudo apt autoremove --purge -y octave"},
|
||||
{"name":"安装WPS", "command":"""wget --referer="https://www.wps.cn/product/wpslinux" \$(curl -L https://linux.wps.cn/ | grep -oP 'href="\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/wps.deb && sudo apt update && sudo apt install -y /tmp/wps.deb; rm /tmp/wps.deb"""},
|
||||
{"name":"安装WPS", "command":r"""cat << 'EOF' | sh && sudo apt update && sudo apt install -y /tmp/wps.deb
|
||||
url=$(curl -L https://linux.wps.cn/ | grep -oP 'href="\K[^"]*arm64\.deb' | head -n 1)
|
||||
wget "${url}?k=$(eval echo -n '7f8faaaa468174dc1c9cd62e5f218a5b/$(echo -n ${url} | cut -d/ -f4-)0x7f53d55201314' | md5sum -t | cut -d' ' -f1)&t=0x7f53d55201314" --header="User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:109.0) Gecko/20100101 Firefox/115.0" --header="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" --header="Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2" --header="Accept-Encoding: gzip, deflate, br" --header="Connection: keep-alive" --header="Referer: https://www.wps.cn/" --header="Upgrade-Insecure-Requests: 1" --header="Sec-Fetch-Dest: document" --header="Sec-Fetch-Mode: navigate" --header="Sec-Fetch-Site: cross-site" --header="Sec-Fetch-User: ?1" -O /tmp/wps.deb
|
||||
EOF
|
||||
rm /tmp/wps.deb"""},
|
||||
{"name":"卸载WPS", "command":"sudo apt autoremove --purge -y wps-office"},
|
||||
{"name":"安装CAJViewer", "command":"wget https://download.cnki.net/net.cnki.cajviewer_1.3.20-1_arm64.deb -O /tmp/caj.deb && sudo apt update && sudo apt install -y /tmp/caj.deb && bash /home/tiny/.local/share/tiny/caj/postinst; rm /tmp/caj.deb"},
|
||||
{"name":"卸载CAJViewer", "command":"sudo apt autoremove --purge -y net.cnki.cajviewer && bash /home/tiny/.local/share/tiny/caj/postrm"},
|
||||
{"name":"安装亿图图示", "command":"wget https://www.edrawsoft.cn/2download/aarch64/edrawmax_11.5.6-3_arm64.deb -O /tmp/edraw.deb && sudo apt update && sudo apt install -y /tmp/edraw.deb && bash /home/tiny/.local/share/tiny/edraw/postinst; rm /tmp/edraw.deb"},
|
||||
{"name":"安装亿图图示", "command":"wget https://www.edrawsoft.cn/2download/aarch64/edrawmax_12.6.1-1_arm64_binner.deb -O /tmp/edraw.deb && sudo apt update && sudo apt install -y /tmp/edraw.deb && bash /home/tiny/.local/share/tiny/edraw/postinst; rm /tmp/edraw.deb"},
|
||||
{"name":"卸载亿图图示", "command":"sudo apt autoremove --purge -y edrawmax libldap-2.4-2"},
|
||||
{"name":"安装QQ", "command":"""wget \$(curl -L https://cdn-go.cn/qq-web/im.qq.com_new/latest/rainbow/linuxQQDownload.js | grep -oP 'deb":"\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/qq.deb && sudo apt update && sudo apt install -y /tmp/qq.deb && sed -i 's#Exec=/opt/QQ/qq %U#Exec=/opt/QQ/qq --no-sandbox %U#g' /usr/share/applications/qq.desktop; rm /tmp/qq.deb"""},
|
||||
{"name":"卸载QQ", "command":"sudo apt autoremove --purge -y linuxqq"},
|
||||
{"name":"安装UOS微信", "command":"wget https://home-store-packages.uniontech.com/appstore/pool/appstore/c/com.tencent.weixin/com.tencent.weixin_2.1.9_arm64.deb -O /tmp/wechat.deb && sudo apt update && sudo apt install -y /tmp/wechat.deb /home/tiny/.local/share/tiny/wechat/deepin-elf-verify_all.deb /home/tiny/.local/share/tiny/wechat/libssl1.1_1.1.1n-0+deb10u6_arm64.deb && sed -i 's#/opt/apps/com.tencent.weixin/files/weixin/weixin#/opt/apps/com.tencent.weixin/files/weixin/weixin --no-sandbox#g' /opt/apps/com.tencent.weixin/files/weixin/weixin.sh && echo '该微信为UOS特供版,只有账号实名且在UOS系统上运行时可用。在使用前请前往全局设置开启UOS伪装。\n如果你使用微信只是为了传输文件,那么可以考虑使用支持SAF的文件管理器(如:质感文件),直接访问小小电脑所有文件。'; rm /tmp/wechat.deb"},
|
||||
{"name":"卸载UOS微信", "command":"sudo apt autoremove --purge -y com.tencent.weixin libssl1.1 deepin-elf-verify"},
|
||||
{"name":"安装UOS微信", "command":"wget https://home-store-packages.uniontech.com/appstore/pool/appstore/c/com.tencent.weixin/com.tencent.weixin_2.1.10_arm64.deb -O /tmp/wechat.deb && sudo apt update && sudo apt install -y /tmp/wechat.deb /home/tiny/.local/share/tiny/wechat/deepin-elf-verify_all.deb /home/tiny/.local/share/tiny/wechat/libssl1.1_1.1.1n-0+deb10u6_arm64.deb && sed -i 's#/opt/apps/com.tencent.weixin/files/weixin/weixin#/opt/apps/com.tencent.weixin/files/weixin/weixin --no-sandbox#g' /opt/apps/com.tencent.weixin/files/weixin/weixin.sh && echo '该微信为UOS特供版,只有账号实名且在UOS系统上运行时可用。在使用前请前往全局设置开启UOS伪装。\n如果你使用微信只是为了传输文件,那么可以考虑使用支持SAF的文件管理器(如:质感文件),直接访问小小电脑所有文件。'; rm /tmp/wechat.deb"},
|
||||
{"name":"卸载UOS微信", "command":"sudo apt autoremove --purge -y com.tencent.weixin deepin-elf-verify"},
|
||||
{"name":"安装钉钉", "command":"""wget \$(curl -L https://g.alicdn.com/dingding/h5-home-download/0.2.4/js/index.js | grep -oP 'url:"\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/dingtalk.deb && sudo apt update && sudo apt install -y /tmp/dingtalk.deb && sed -i 's#\\./com.alibabainc.dingtalk#\\./com.alibabainc.dingtalk --no-sandbox#g' /opt/apps/com.alibabainc.dingtalk/files/Elevator.sh; rm /tmp/dingtalk.deb"""},
|
||||
{"name":"卸载钉钉", "command":"sudo apt autoremove --purge -y com.alibabainc.dingtalk"},
|
||||
{"name":"修复无法编译C语言程序", "command":"sudo apt update && sudo apt reinstall -y libc6-dev"},
|
||||
@@ -470,6 +507,8 @@ class D {
|
||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4)
|
||||
);
|
||||
|
||||
static const MethodChannel avncChannel = MethodChannel("avnc");
|
||||
|
||||
}
|
||||
|
||||
// Global variables
|
||||
@@ -859,7 +898,7 @@ clear""");
|
||||
SystemChrome.restoreSystemUIOverlays();
|
||||
});
|
||||
return Focus(
|
||||
onKey: (node, event) {
|
||||
onKeyEvent: (node, event) {
|
||||
// Allow webview to handle cursor keys. Without this, the
|
||||
// arrow keys seem to get "eaten" by Flutter and therefore
|
||||
// never reach the webview.
|
||||
@@ -883,6 +922,10 @@ clear""");
|
||||
}));
|
||||
}
|
||||
|
||||
static Future<void> launchAvnc() async {
|
||||
await D.avncChannel.invokeMethod("launchUsingUri", {"vncUri": Util.getCurrentProp("vncUri") as String});
|
||||
}
|
||||
|
||||
static Future<void> workflow() async {
|
||||
grantPermissions();
|
||||
await initData();
|
||||
@@ -891,7 +934,7 @@ clear""");
|
||||
setupAudio();
|
||||
launchCurrentContainer();
|
||||
if (Util.getGlobal("autoLaunchVnc") as bool) {
|
||||
waitForConnection().then((value) => launchBrowser());
|
||||
waitForConnection().then((value) => (Util.getGlobal("useAvnc") as bool)?launchAvnc():launchBrowser());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user