mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 16:35:47 +08:00
Add signal 9 info, adjust readme
This commit is contained in:
16
README.md
16
README.md
@@ -40,6 +40,8 @@ assets的文件来源如下:
|
|||||||
- 启动时会尝试挂载手机的一些字体目录(AppFiles/Fonts、Fonts和/system/fonts), 如果这些目录下有字体文件的话会一并加载到系统中,无需额外安装;
|
- 启动时会尝试挂载手机的一些字体目录(AppFiles/Fonts、Fonts和/system/fonts), 如果这些目录下有字体文件的话会一并加载到系统中,无需额外安装;
|
||||||
- 最后采用tar.xz压缩,用split命令分成了xa*等多个文件(低内存设备一次性拷贝大文件会导致软件闪退)。
|
- 最后采用tar.xz压缩,用split命令分成了xa*等多个文件(低内存设备一次性拷贝大文件会导致软件闪退)。
|
||||||
|
|
||||||
|
完整的容器制作过程可以在[这里](https://github.com/Cateners/build-tiny-rootfs)看到。
|
||||||
|
|
||||||
数据包不再在assets中更新,而是随releases提供,主要是为了避免git越来越大
|
数据包不再在assets中更新,而是随releases提供,主要是为了避免git越来越大
|
||||||
|
|
||||||
lib目录:
|
lib目录:
|
||||||
@@ -51,6 +53,20 @@ lib目录:
|
|||||||
- G 全局变量类
|
- G 全局变量类
|
||||||
- Workflow 从软件点开到容器启动的所有步骤
|
- Workflow 从软件点开到容器启动的所有步骤
|
||||||
|
|
||||||
|
## 编译
|
||||||
|
|
||||||
|
你需要配置好flutter和安卓sdk,然后克隆此项目。
|
||||||
|
|
||||||
|
在编译之前,需要在release中下载系统rootfs(或者[自行制作](https://github.com/Cateners/build-tiny-rootfs)),之后使用split命令分割,拷贝到assets。一般我将其分为98MB。
|
||||||
|
|
||||||
|
`split -b 98M debian.tar.xz`
|
||||||
|
|
||||||
|
然后修改workflow的代码,找到复制资源的部分,把生成的xa\*名字写进去(我还不知道怎么写代码识别有多少个xa*文件)
|
||||||
|
|
||||||
|
接下来就可以编译了。我使用的命令如下:
|
||||||
|
|
||||||
|
`flutter build apk --target-platform android-arm64 --split-per-abi --obfuscate --split-debug-info=tiny_computer/sdi`
|
||||||
|
|
||||||
## 目前已知bug
|
## 目前已知bug
|
||||||
|
|
||||||
多用户/分身情形无法sudo, 其它见issue
|
多用户/分身情形无法sudo, 其它见issue
|
||||||
|
|||||||
@@ -847,7 +847,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
bannerAdsFailedToLoad = true;
|
bannerAdsFailedToLoad = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
), Expanded(flex: 1, child: AnimatedSwitcher(
|
), Expanded(child: AnimatedSwitcher(
|
||||||
duration: const Duration(milliseconds: 256),
|
duration: const Duration(milliseconds: 256),
|
||||||
child: [
|
child: [
|
||||||
Column(children: [Expanded(child: forceScaleGestureDetector(onScaleUpdate: (details) {
|
Column(children: [Expanded(child: forceScaleGestureDetector(onScaleUpdate: (details) {
|
||||||
@@ -857,8 +857,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
}, onScaleEnd: (details) async {
|
}, onScaleEnd: (details) async {
|
||||||
await G.prefs.setDouble("termFontScale", G.termFontScale);
|
await G.prefs.setDouble("termFontScale", G.termFontScale);
|
||||||
}, child: TerminalView(G.termPtys[G.currentContainer]!.terminal, textScaleFactor: G.termFontScale, keyboardType: TextInputType.multiline,))),
|
}, child: TerminalView(G.termPtys[G.currentContainer]!.terminal, textScaleFactor: G.termFontScale, keyboardType: TextInputType.multiline,))),
|
||||||
(Util.getGlobal("isTerminalCommandsEnabled") as bool)?Padding(padding: const EdgeInsets.all(8), child:
|
(Util.getGlobal("isTerminalCommandsEnabled") as bool)?Padding(padding: const EdgeInsets.all(8), child: Row(children: [AnimatedBuilder(
|
||||||
SingleChildScrollView(restorationId: "commands-bar", scrollDirection: Axis.horizontal, child: Row(children: [AnimatedBuilder(
|
|
||||||
animation: G.keyboard,
|
animation: G.keyboard,
|
||||||
builder: (context, child) => ToggleButtons(
|
builder: (context, child) => ToggleButtons(
|
||||||
constraints: const BoxConstraints(minWidth: 32, minHeight: 24),
|
constraints: const BoxConstraints(minWidth: 32, minHeight: 24),
|
||||||
@@ -880,54 +879,15 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
},
|
},
|
||||||
children: const [Text('Ctrl'), Text('Alt'), Text('Shift')],
|
children: const [Text('Ctrl'), Text('Alt'), Text('Shift')],
|
||||||
),
|
),
|
||||||
//TODO: 丑陋的实现,不知道列表有没有更方便的操作
|
),
|
||||||
), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
SizedBox.fromSize(size: const Size.square(8)),
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.escape);
|
Expanded(child: SizedBox(height: 24, child: ListView.separated(scrollDirection: Axis.horizontal, itemBuilder:(context, index) {
|
||||||
}, child: const Text("Esc")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
return OutlinedButton(style: controlButtonStyle, onPressed: () {
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.tab);
|
G.termPtys[G.currentContainer]!.terminal.keyInput(D.termCommands[index]["key"]! as TerminalKey);
|
||||||
}, child: const Text("Tab")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
}, child: Text(D.termCommands[index]["name"]! as String));
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.arrowUp);
|
}, separatorBuilder:(context, index) {
|
||||||
}, child: const Text("↑")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
return SizedBox.fromSize(size: const Size.square(4));
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.arrowDown);
|
}, itemCount: D.termCommands.length))), SizedBox.fromSize(size: const Size(72, 0))])):SizedBox.fromSize(size: const Size.square(0))
|
||||||
}, child: const Text("↓")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.arrowLeft);
|
|
||||||
}, child: const Text("←")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.arrowRight);
|
|
||||||
}, child: const Text("→")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.delete);
|
|
||||||
}, child: const Text("Del")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.pageUp);
|
|
||||||
}, child: const Text("PgUp")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.pageDown);
|
|
||||||
}, child: const Text("PgDn")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.home);
|
|
||||||
}, child: const Text("Home")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.end);
|
|
||||||
}, child: const Text("End")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f1);
|
|
||||||
}, child: const Text("F1")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f2);
|
|
||||||
}, child: const Text("F2")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f3);
|
|
||||||
}, child: const Text("F3")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f4);
|
|
||||||
}, child: const Text("F4")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f5);
|
|
||||||
}, child: const Text("F5")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f6);
|
|
||||||
}, child: const Text("F6")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f7);
|
|
||||||
}, child: const Text("F7")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f8);
|
|
||||||
}, child: const Text("F8")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f9);
|
|
||||||
}, child: const Text("F9")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f10);
|
|
||||||
}, child: const Text("F10")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f11);
|
|
||||||
}, child: const Text("F11")), SizedBox.fromSize(size: const Size.square(4)), OutlinedButton(style: controlButtonStyle, onPressed: () {
|
|
||||||
G.termPtys[G.currentContainer]!.terminal.keyInput(TerminalKey.f12);
|
|
||||||
}, child: const Text("F12")), SizedBox.fromSize(size: const Size(72, 0))]))):SizedBox.fromSize(size: const Size.square(0))
|
|
||||||
]), Padding(
|
]), Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Scrollbar(child: SingleChildScrollView(restorationId: "control-scroll", child: Column(
|
child: Scrollbar(child: SingleChildScrollView(restorationId: "control-scroll", child: Column(
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class Util {
|
|||||||
case "termFontScale" : return b ? G.prefs.getDouble(key)! : (value){G.prefs.setDouble(key, value); return value;}(1.0);
|
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;}(0);
|
||||||
case "isStickyKey" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
|
case "isStickyKey" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
|
||||||
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 -i 0:0 -vf scale=iw/2:-1 -rtsp_transport udp -f rtsp rtsp://127.0.0.1:8554/stream");
|
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 "containersInfo" : return G.prefs.getStringList(key)!;
|
case "containersInfo" : return G.prefs.getStringList(key)!;
|
||||||
case "adsBonus" : return b ? G.prefs.getStringList(key)! : (value){G.prefs.setStringList(key, value); return value;}([].cast<String>());
|
case "adsBonus" : return b ? G.prefs.getStringList(key)! : (value){G.prefs.setStringList(key, value); return value;}([].cast<String>());
|
||||||
}
|
}
|
||||||
@@ -267,6 +267,7 @@ class TermPty {
|
|||||||
Navigator.push(G.homePageStateContext, MaterialPageRoute(builder: (context) {
|
Navigator.push(G.homePageStateContext, MaterialPageRoute(builder: (context) {
|
||||||
const TextStyle ts = TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.normal);
|
const TextStyle ts = TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.normal);
|
||||||
const String helperLink = "https://www.vmos.cn/zhushou.htm";
|
const String helperLink = "https://www.vmos.cn/zhushou.htm";
|
||||||
|
const String helperLink2 = "https://b23.tv/WwqOqW6";
|
||||||
return Scaffold(backgroundColor: Colors.deepPurple,
|
return Scaffold(backgroundColor: Colors.deepPurple,
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Scrollbar(child:
|
child: Scrollbar(child:
|
||||||
@@ -285,7 +286,18 @@ class TermPty {
|
|||||||
},))
|
},))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, child: const Text("复制", style: ts, textAlign: TextAlign.center))
|
}, child: const Text("复制", style: ts, textAlign: TextAlign.center)),
|
||||||
|
const Text("如果不能解决请参考此教程: ", style: ts, textAlign: TextAlign.center),
|
||||||
|
OutlinedButton(onPressed: () {
|
||||||
|
FlutterClipboard.copy(helperLink2).then(( value ) {
|
||||||
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: const Text("已复制"), action: SnackBarAction(label: "跳转", onPressed: () {
|
||||||
|
launchUrl(Uri.parse(helperLink2), mode: LaunchMode.externalApplication);
|
||||||
|
},))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, child: const Text("查看", style: ts, textAlign: TextAlign.center))
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -326,7 +338,7 @@ class D {
|
|||||||
{"name":"卸载视频剪辑软件Kdenlive", "command":"sudo apt autoremove --purge -y kdenlive"},
|
{"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 update && sudo apt install -y octave"},
|
||||||
{"name":"卸载科学计算软件Octave", "command":"sudo apt autoremove --purge -y octave"},
|
{"name":"卸载科学计算软件Octave", "command":"sudo apt autoremove --purge -y octave"},
|
||||||
{"name":"安装WPS", "command":"wget https://wps-linux-personal.wpscdn.cn/wps/download/ep/Linux2019/11704/wps-office_11.1.0.11704_arm64.deb -O /tmp/wps.deb && sudo apt update && sudo apt install -y /tmp/wps.deb; rm /tmp/wps.deb"},
|
{"name":"安装WPS", "command":"wget https://wps-linux-personal.wpscdn.cn/wps/download/ep/Linux2019/11708/wps-office_11.1.0.11708_arm64.deb -O /tmp/wps.deb && sudo apt update && sudo apt install -y /tmp/wps.deb; rm /tmp/wps.deb"},
|
||||||
{"name":"卸载WPS", "command":"sudo apt autoremove --purge -y wps-office"},
|
{"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":"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":"卸载CAJViewer", "command":"sudo apt autoremove --purge -y net.cnki.cajviewer && bash /home/tiny/.local/share/tiny/caj/postrm"},
|
||||||
@@ -340,6 +352,32 @@ class D {
|
|||||||
{"name":"拉流测试", "command":"ffplay rtsp://127.0.0.1:8554/stream &"},
|
{"name":"拉流测试", "command":"ffplay rtsp://127.0.0.1:8554/stream &"},
|
||||||
{"name":"关机", "command":"stopvnc\nexit\nexit"},
|
{"name":"关机", "command":"stopvnc\nexit\nexit"},
|
||||||
{"name":"???", "command":"timeout 8 cmatrix"}];
|
{"name":"???", "command":"timeout 8 cmatrix"}];
|
||||||
|
//默认快捷指令
|
||||||
|
static const termCommands = [
|
||||||
|
{"name": "Esc", "key": TerminalKey.escape},
|
||||||
|
{"name": "Tab", "key": TerminalKey.tab},
|
||||||
|
{"name": "↑", "key": TerminalKey.arrowUp},
|
||||||
|
{"name": "↓", "key": TerminalKey.arrowDown},
|
||||||
|
{"name": "←", "key": TerminalKey.arrowLeft},
|
||||||
|
{"name": "→", "key": TerminalKey.arrowRight},
|
||||||
|
{"name": "Del", "key": TerminalKey.delete},
|
||||||
|
{"name": "PgUp", "key": TerminalKey.pageUp},
|
||||||
|
{"name": "PgDn", "key": TerminalKey.pageDown},
|
||||||
|
{"name": "Home", "key": TerminalKey.home},
|
||||||
|
{"name": "End", "key": TerminalKey.end},
|
||||||
|
{"name": "F1", "key": TerminalKey.f1},
|
||||||
|
{"name": "F2", "key": TerminalKey.f2},
|
||||||
|
{"name": "F3", "key": TerminalKey.f3},
|
||||||
|
{"name": "F4", "key": TerminalKey.f4},
|
||||||
|
{"name": "F5", "key": TerminalKey.f5},
|
||||||
|
{"name": "F6", "key": TerminalKey.f6},
|
||||||
|
{"name": "F7", "key": TerminalKey.f7},
|
||||||
|
{"name": "F8", "key": TerminalKey.f8},
|
||||||
|
{"name": "F9", "key": TerminalKey.f9},
|
||||||
|
{"name": "F10", "key": TerminalKey.f10},
|
||||||
|
{"name": "F11", "key": TerminalKey.f11},
|
||||||
|
{"name": "F12", "key": TerminalKey.f12},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.10+1
|
version: 1.0.10+2
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.1.0 <4.0.0'
|
sdk: '>=3.1.0 <4.0.0'
|
||||||
|
|||||||
Reference in New Issue
Block a user