mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 08:35:46 +08:00
Ads removal
This commit is contained in:
186
lib/main.dart
186
lib/main.dart
@@ -39,8 +39,6 @@ import 'package:xterm/xterm.dart';
|
|||||||
//import 'package:xterm/flutter.dart';
|
//import 'package:xterm/flutter.dart';
|
||||||
import 'package:tiny_computer/workflow.dart';
|
import 'package:tiny_computer/workflow.dart';
|
||||||
|
|
||||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
|
||||||
|
|
||||||
import 'package:ffmpeg_kit_flutter_full_gpl/ffmpeg_kit.dart';
|
import 'package:ffmpeg_kit_flutter_full_gpl/ffmpeg_kit.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@@ -117,7 +115,7 @@ class SettingPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _SettingPageState extends State<SettingPage> {
|
class _SettingPageState extends State<SettingPage> {
|
||||||
|
|
||||||
final List<bool> _expandState = [false, false, false, false, false, false, false, false];
|
final List<bool> _expandState = [false, false, false, false, false, false, false];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -201,18 +199,10 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
ExpansionPanel(
|
ExpansionPanel(
|
||||||
isExpanded: _expandState[1],
|
isExpanded: _expandState[1],
|
||||||
headerBuilder: ((context, isExpanded) {
|
headerBuilder: ((context, isExpanded) {
|
||||||
return const ListTile(title: Text("全局设置"), subtitle: Text("在这里关广告、开启终端编辑"));
|
return const ListTile(title: Text("全局设置"), subtitle: Text("在这里开启终端编辑"));
|
||||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||||
TextFormField(autovalidateMode: AutovalidateMode.onUserInteraction, initialValue: (Util.getGlobal("termMaxLines") as int).toString(), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "终端最大行数(重启软件生效)"), readOnly: Util.shouldWatchAds(D.adsRequired["changeTermMaxLines"]!),
|
TextFormField(autovalidateMode: AutovalidateMode.onUserInteraction, initialValue: (Util.getGlobal("termMaxLines") as int).toString(), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "终端最大行数(重启软件生效)"),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
onTap: () {
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeTermMaxLines"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看六次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
return Util.validateBetween(value, 1024, 2147483647, () async {
|
return Util.validateBetween(value, 1024, 2147483647, () async {
|
||||||
await G.prefs.setInt("termMaxLines", int.parse(value!));
|
await G.prefs.setInt("termMaxLines", int.parse(value!));
|
||||||
@@ -228,43 +218,12 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
const SizedBox.square(dimension: 16),
|
const SizedBox.square(dimension: 16),
|
||||||
SwitchListTile(title: const Text("关闭横幅广告"), value: Util.getGlobal("isBannerAdsClosed") as bool, onChanged:(value) {
|
|
||||||
if (value && Util.shouldWatchAds(D.adsRequired["closeBannerAds"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看五次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
G.prefs.setBool("isBannerAdsClosed", value);
|
|
||||||
setState(() {
|
|
||||||
G.bannerAdsChange.value = !G.bannerAdsChange.value;
|
|
||||||
});
|
|
||||||
},),
|
|
||||||
const SizedBox.square(dimension: 8),
|
|
||||||
SwitchListTile(title: const Text("启用终端"), value: Util.getGlobal("isTerminalWriteEnabled") as bool, onChanged:(value) {
|
SwitchListTile(title: const Text("启用终端"), value: Util.getGlobal("isTerminalWriteEnabled") as bool, onChanged:(value) {
|
||||||
if (value && Util.shouldWatchAds(D.adsRequired["enableTerminalWrite"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: const Text("观看两次视频广告永久解锁><"), action: SnackBarAction(label: "啊?", onPressed: () {
|
|
||||||
G.prefs.setBool("isTerminalWriteEnabled", value);
|
|
||||||
setState(() {});
|
|
||||||
},))
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
G.prefs.setBool("isTerminalWriteEnabled", value);
|
G.prefs.setBool("isTerminalWriteEnabled", value);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},),
|
},),
|
||||||
const SizedBox.square(dimension: 8),
|
const SizedBox.square(dimension: 8),
|
||||||
SwitchListTile(title: const Text("启用终端小键盘"), value: Util.getGlobal("isTerminalCommandsEnabled") as bool, onChanged:(value) {
|
SwitchListTile(title: const Text("启用终端小键盘"), value: Util.getGlobal("isTerminalCommandsEnabled") as bool, onChanged:(value) {
|
||||||
if (value && Util.shouldWatchAds(D.adsRequired["enableTerminalCommands"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看三次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
G.prefs.setBool("isTerminalCommandsEnabled", value);
|
G.prefs.setBool("isTerminalCommandsEnabled", value);
|
||||||
setState(() {
|
setState(() {
|
||||||
G.terminalPageChange.value = !G.terminalPageChange.value;
|
G.terminalPageChange.value = !G.terminalPageChange.value;
|
||||||
@@ -380,15 +339,7 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
|||||||
|
|
||||||
一些软件可能会存在显示问题,或者显示速度变慢。"""),
|
一些软件可能会存在显示问题,或者显示速度变慢。"""),
|
||||||
const SizedBox.square(dimension: 16),
|
const SizedBox.square(dimension: 16),
|
||||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultHidpiOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "HiDPI环境变量"), readOnly: Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!),
|
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultHidpiOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "HiDPI环境变量"),
|
||||||
onTap: () {
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看十二次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
await G.prefs.setString("defaultHidpiOpt", value);
|
await G.prefs.setString("defaultHidpiOpt", value);
|
||||||
},
|
},
|
||||||
@@ -440,15 +391,7 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
const SizedBox.square(dimension: 16),
|
const SizedBox.square(dimension: 16),
|
||||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultFFmpegCommand") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "ffmpeg推流命令"), readOnly: Util.shouldWatchAds(D.adsRequired["changeFFmpegCommand"]!),
|
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultFFmpegCommand") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "ffmpeg推流命令"),
|
||||||
onTap: () {
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeFFmpegCommand"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看八次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
await G.prefs.setString("defaultFFmpegCommand", value);
|
await G.prefs.setString("defaultFFmpegCommand", value);
|
||||||
},
|
},
|
||||||
@@ -558,13 +501,6 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
|||||||
),
|
),
|
||||||
const SizedBox.square(dimension: 8),
|
const SizedBox.square(dimension: 8),
|
||||||
SwitchListTile(title: const Text("启用virgl加速"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("virgl") as bool, onChanged:(value) {
|
SwitchListTile(title: const Text("启用virgl加速"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("virgl") as bool, onChanged:(value) {
|
||||||
if (value && Util.shouldWatchAds(D.adsRequired["enableVirgl"]!)) {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("观看十次视频广告永久解锁><"))
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
G.prefs.setBool("virgl", value);
|
G.prefs.setBool("virgl", value);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},),
|
},),
|
||||||
@@ -579,9 +515,9 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
|||||||
|
|
||||||
运行windows程序需要经过架构和系统两层模拟,不要对运行速度抱有期待。程序崩溃也是常有的。
|
运行windows程序需要经过架构和系统两层模拟,不要对运行速度抱有期待。程序崩溃也是常有的。
|
||||||
|
|
||||||
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
|
建议将要运行的Windows程序连同程序文件夹移至桌面运行。
|
||||||
|
|
||||||
如果不耐烦可以去看个广告消磨时间(bushi)
|
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
|
||||||
|
|
||||||
或者寻找该windows软件官方是否提供linux arm64版本。
|
或者寻找该windows软件官方是否提供linux arm64版本。
|
||||||
|
|
||||||
@@ -704,35 +640,6 @@ fi""");
|
|||||||
},),
|
},),
|
||||||
const SizedBox.square(dimension: 16),
|
const SizedBox.square(dimension: 16),
|
||||||
],))),
|
],))),
|
||||||
ExpansionPanel(
|
|
||||||
isExpanded: _expandState[7],
|
|
||||||
headerBuilder: ((context, isExpanded) {
|
|
||||||
return const ListTile(title: Text("广告记录"), subtitle: Text("在这里看广告"));
|
|
||||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
|
||||||
OutlinedButton(child: const Text("看一个广告"), onPressed: () {
|
|
||||||
if (AdManager.placements[AdManager.rewardedVideoAdPlacementId]!) {
|
|
||||||
AdManager.showAd(AdManager.rewardedVideoAdPlacementId, () {
|
|
||||||
final bonus = Util.getRandomBonus();
|
|
||||||
Util.applyBonus(bonus);
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text("你获得了 ${bonus["name"]}*${bonus["amount"]}"))
|
|
||||||
);
|
|
||||||
setState(() {});
|
|
||||||
}, () {
|
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text("已经看5个广告了, 今天也非常感谢><"))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
const SizedBox.square(dimension: 8),
|
|
||||||
Text(Util.getGlobal("adsBonus").map((element) {
|
|
||||||
final e = jsonDecode(element);
|
|
||||||
return e["amount"]==0?"":"${e["name"]}*${e["amount"]}\n";
|
|
||||||
}).join())
|
|
||||||
],))),
|
|
||||||
],);
|
],);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1159,47 +1066,19 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
------------
|
|
||||||
unity_ads_plugin
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2021 Pavel Zaichyk
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
"""))),
|
"""))),
|
||||||
ExpansionPanel(
|
ExpansionPanel(
|
||||||
isExpanded: _expandState[2],
|
isExpanded: _expandState[2],
|
||||||
headerBuilder: ((context, isExpanded) {
|
headerBuilder: ((context, isExpanded) {
|
||||||
return const ListTile(title: Text("隐私政策"));
|
return const ListTile(title: Text("隐私政策"));
|
||||||
}), body: const Padding(padding: EdgeInsets.all(8), child: Text("""
|
}), body: const Padding(padding: EdgeInsets.all(8), child: Text("""
|
||||||
除由Unity提供的广告功能外, 本软件不会收集你的隐私信息。
|
本软件不会收集你的隐私信息。
|
||||||
|
|
||||||
当然,你在容器系统内部安装或使用的软件行为(包括通过快捷指令)就不受我控制了,我不对其负责。
|
当然,你在容器系统内部安装或使用的软件行为(包括通过快捷指令)就不受我控制了,我不对其负责。
|
||||||
|
|
||||||
本软件申请的权限用于以下目的:
|
本软件申请的权限用于以下目的:
|
||||||
文件相关权限:用于系统访问手机目录;
|
文件相关权限:用于系统访问手机目录;
|
||||||
相机和麦克风:用于推流,默认不会开启。
|
相机和麦克风:用于推流,默认不会开启。
|
||||||
|
|
||||||
关于广告获取隐私信息的说明, 在第一次看广告时Unity会向你做出告知。
|
|
||||||
届时你可以选择要向Unity提供哪些信息。
|
|
||||||
"""))),
|
"""))),
|
||||||
ExpansionPanel(
|
ExpansionPanel(
|
||||||
isExpanded: _expandState[3],
|
isExpanded: _expandState[3],
|
||||||
@@ -1221,36 +1100,7 @@ SOFTWARE.
|
|||||||
}), body: Column(
|
}), body: Column(
|
||||||
children: [
|
children: [
|
||||||
const Padding(padding: EdgeInsets.all(8), child: Text("""
|
const Padding(padding: EdgeInsets.all(8), child: Text("""
|
||||||
这个软件预计会有一些广告
|
如果认为好用的话,可以推荐给其他人用噢!
|
||||||
分为横幅广告和视频广告
|
|
||||||
横幅广告在终端和控制页面的顶端出现
|
|
||||||
(但不知道是不是因为代码没写对
|
|
||||||
反正我从没见横幅广告成功加载过)
|
|
||||||
视频广告在需要解锁某些功能时自行观看
|
|
||||||
|
|
||||||
这些功能需要累计完整观看对应数目广告后永久解锁:
|
|
||||||
启用终端: 观看2个广告
|
|
||||||
启用小键盘: 观看3个广告
|
|
||||||
关闭横幅广告: 观看5个广告
|
|
||||||
终端最大行数修改: 观看6个广告
|
|
||||||
推流参数修改: 观看8个广告
|
|
||||||
启用virgl加速: 观看10个广告
|
|
||||||
HiDPI环境变量修改: 观看12个广告
|
|
||||||
|
|
||||||
我设置了每天最多可以看5个广告。
|
|
||||||
只要看满1个广告, 就可以在本次使用期间临时解锁全部功能。
|
|
||||||
只要看满2个广告, 就可以在当日使用期间临时解锁全部功能。
|
|
||||||
|
|
||||||
总之为了良好的体验
|
|
||||||
在图形界面是不会出现广告的
|
|
||||||
这点还请放心
|
|
||||||
|
|
||||||
---注意事项---
|
|
||||||
|
|
||||||
我注意到Unity提供了一些不那么合适的广告
|
|
||||||
一般如果我看到这些广告就在后台直接禁了
|
|
||||||
不过也可能有漏网之鱼
|
|
||||||
可以联系我禁掉
|
|
||||||
""")),
|
""")),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -1506,20 +1356,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(isLoadingComplete?Util.getCurrentProp("name"):widget.title),
|
title: Text(isLoadingComplete?Util.getCurrentProp("name"):widget.title),
|
||||||
),
|
),
|
||||||
body: isLoadingComplete?Column(mainAxisSize: MainAxisSize.min, children: [
|
body: isLoadingComplete?
|
||||||
ValueListenableBuilder(valueListenable: G.bannerAdsChange, builder:(context, value, child) {
|
Expanded(child: ValueListenableBuilder(valueListenable: G.pageIndex, builder: (context, value, child) {
|
||||||
return (Util.getGlobal("isBannerAdsClosed") as bool)||bannerAdsFailedToLoad?const SizedBox.square(dimension: 0):UnityBannerAd(
|
|
||||||
placementId: AdManager.bannerAdPlacementId,
|
|
||||||
onLoad: (placementId) => debugPrint('Banner loaded: $placementId'),
|
|
||||||
onClick: (placementId) => debugPrint('Banner clicked: $placementId'),
|
|
||||||
onFailed: (placementId, error, message) {
|
|
||||||
debugPrint('Banner Ad $placementId failed: $error $message');
|
|
||||||
setState(() {
|
|
||||||
bannerAdsFailedToLoad = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}), Expanded(child: ValueListenableBuilder(valueListenable: G.pageIndex, builder: (context, value, child) {
|
|
||||||
return IndexedStack(index: G.pageIndex.value, children: const [TerminalPage(), Padding(
|
return IndexedStack(index: G.pageIndex.value, children: const [TerminalPage(), Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: EdgeInsets.all(8),
|
||||||
child: Scrollbar(child: SingleChildScrollView(restorationId: "control-scroll", child: Column(
|
child: Scrollbar(child: SingleChildScrollView(restorationId: "control-scroll", child: Column(
|
||||||
@@ -1544,7 +1382,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
]
|
]
|
||||||
)))
|
)))
|
||||||
)]);
|
)]);
|
||||||
}))]):const LoadingPage(),
|
})):const LoadingPage(),
|
||||||
bottomNavigationBar: ValueListenableBuilder(valueListenable: G.pageIndex, builder:(context, value, child) {
|
bottomNavigationBar: ValueListenableBuilder(valueListenable: G.pageIndex, builder:(context, value, child) {
|
||||||
return Visibility(visible: isLoadingComplete,
|
return Visibility(visible: isLoadingComplete,
|
||||||
// child: BottomNavigationBar(currentIndex: G.pageIndex.value,
|
// child: BottomNavigationBar(currentIndex: G.pageIndex.value,
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ import 'package:permission_handler/permission_handler.dart';
|
|||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
|
||||||
|
|
||||||
import 'package:clipboard/clipboard.dart';
|
import 'package:clipboard/clipboard.dart';
|
||||||
|
|
||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
@@ -77,14 +75,10 @@ class Util {
|
|||||||
//int defaultAudioPort = 4718: 默认pulseaudio端口(为了避免和其它软件冲突改成4718了,原默认4713)
|
//int defaultAudioPort = 4718: 默认pulseaudio端口(为了避免和其它软件冲突改成4718了,原默认4713)
|
||||||
//bool autoLaunchVnc = true: 是否自动启动VNC并跳转
|
//bool autoLaunchVnc = true: 是否自动启动VNC并跳转
|
||||||
//String lastDate: 上次启动软件的日期,yyyy-MM-dd
|
//String lastDate: 上次启动软件的日期,yyyy-MM-dd
|
||||||
//int adsWatchedToday: 今日视频广告观看数量
|
|
||||||
//int adsWatchedTotal: 视频广告观看数量
|
|
||||||
//bool isBannerAdsClosed = false
|
|
||||||
//bool isTerminalWriteEnabled = false
|
//bool isTerminalWriteEnabled = false
|
||||||
//bool isTerminalCommandsEnabled = false
|
//bool isTerminalCommandsEnabled = false
|
||||||
//int termMaxLines = 4095 终端最大行数
|
//int termMaxLines = 4095 终端最大行数
|
||||||
//double termFontScale = 1 终端字体大小
|
//double termFontScale = 1 终端字体大小
|
||||||
//int vip = 0 用户等级,vip免广告,你要改吗?(ToT)
|
|
||||||
//bool isStickyKey = true 终端ctrl, shift, alt键是否粘滞
|
//bool isStickyKey = true 终端ctrl, shift, alt键是否粘滞
|
||||||
//String defaultFFmpegCommand 默认推流命令
|
//String defaultFFmpegCommand 默认推流命令
|
||||||
//String defaultVirglCommand 默认virgl参数
|
//String defaultVirglCommand 默认virgl参数
|
||||||
@@ -103,8 +97,6 @@ class Util {
|
|||||||
//String[] containersInfo: 所有容器信息(json)
|
//String[] containersInfo: 所有容器信息(json)
|
||||||
//{name, boot:"\$DATA_DIR/bin/proot ...", vnc:"startnovnc", vncUrl:"...", commands:[{name:"更新和升级", command:"apt update -y && apt upgrade -y"},
|
//{name, boot:"\$DATA_DIR/bin/proot ...", vnc:"startnovnc", vncUrl:"...", commands:[{name:"更新和升级", command:"apt update -y && apt upgrade -y"},
|
||||||
// bind:[{name:"U盘", src:"/storage/xxxx", dst:"/media/meow"}]...]}
|
// bind:[{name:"U盘", src:"/storage/xxxx", dst:"/media/meow"}]...]}
|
||||||
//String[] adsBonus: 观看广告获取的奖励(json)
|
|
||||||
//{name: "xxx", amount: xxx}
|
|
||||||
//TODO: 这么写还是不对劲,有空改成类试试?
|
//TODO: 这么写还是不对劲,有空改成类试试?
|
||||||
static dynamic getGlobal(String key) {
|
static dynamic getGlobal(String key) {
|
||||||
bool b = G.prefs.containsKey(key);
|
bool b = G.prefs.containsKey(key);
|
||||||
@@ -113,14 +105,10 @@ class Util {
|
|||||||
case "defaultAudioPort" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(4718);
|
case "defaultAudioPort" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(4718);
|
||||||
case "autoLaunchVnc" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
|
case "autoLaunchVnc" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
|
||||||
case "lastDate" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("1970-01-01");
|
case "lastDate" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("1970-01-01");
|
||||||
case "adsWatchedToday" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(0);
|
|
||||||
case "adsWatchedTotal" : return b ? G.prefs.getInt(key)! : (value){G.prefs.setInt(key, value); return value;}(0);
|
|
||||||
case "isBannerAdsClosed" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
|
||||||
case "isTerminalWriteEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
case "isTerminalWriteEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||||
case "isTerminalCommandsEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
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 "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 "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;}(1);
|
|
||||||
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 "reinstallBootstrap" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
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);
|
case "getifaddrsBridge" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||||
@@ -136,7 +124,6 @@ class Util {
|
|||||||
case "defaultVirglOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GALLIUM_DRIVER=virpipe");
|
case "defaultVirglOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GALLIUM_DRIVER=virpipe");
|
||||||
case "defaultHidpiOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GDK_SCALE=2 QT_FONT_DPI=192");
|
case "defaultHidpiOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GDK_SCALE=2 QT_FONT_DPI=192");
|
||||||
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>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,43 +173,6 @@ class Util {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回单个G.bonusTable定义的item
|
|
||||||
static Map<String, dynamic> getRandomBonus() {
|
|
||||||
final random = Random();
|
|
||||||
final totalWeight = D.bonusTable.fold(0.0, (sum, item) => sum + item['weight']);
|
|
||||||
final randomIndex = random.nextDouble() * totalWeight;
|
|
||||||
var cumulativeWeight = 0.0;
|
|
||||||
for (final item in D.bonusTable) {
|
|
||||||
cumulativeWeight += item['weight'];
|
|
||||||
if (randomIndex <= cumulativeWeight) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return D.bonusTable[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
//由getRandomBonus返回的数据
|
|
||||||
static Future<void> applyBonus(Map<String, dynamic> bonus) async {
|
|
||||||
bool flag = false;
|
|
||||||
List<String> ret = Util.getGlobal("adsBonus").map((e) {
|
|
||||||
Map<String, dynamic> item = jsonDecode(e);
|
|
||||||
return (item["name"] == bonus["name"])?
|
|
||||||
jsonEncode(item..update("amount", (v) {
|
|
||||||
flag = true;
|
|
||||||
return v + bonus["amount"];
|
|
||||||
})):e;
|
|
||||||
}).toList().cast<String>();
|
|
||||||
if (!flag) {
|
|
||||||
ret.add("""{"name": "${bonus["name"]}", "amount": ${bonus["amount"]}}""");
|
|
||||||
}
|
|
||||||
await G.prefs.setStringList("adsBonus", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
//根据已看广告量判断是否应该继续看广告
|
|
||||||
static bool shouldWatchAds(int expectNum) {
|
|
||||||
return ((Util.getGlobal("adsWatchedTotal") as int) < expectNum) && ((Util.getGlobal("vip") as int) < 1) && ((Util.getGlobal("adsWatchedToday") as int) < D.adsRequired["unlockToday"]!) && (G.adsWatchedThisTime < D.adsRequired["unlockOnce"]!);
|
|
||||||
}
|
|
||||||
|
|
||||||
//限定字符串在min和max之间, 给文本框的validator
|
//限定字符串在min和max之间, 给文本框的validator
|
||||||
static String? validateBetween(String? value, int min, int max, Function opr) {
|
static String? validateBetween(String? value, int min, int max, Function opr) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
@@ -524,34 +474,6 @@ rm /tmp/wps.deb"""},
|
|||||||
{"name": "F12", "key": TerminalKey.f12},
|
{"name": "F12", "key": TerminalKey.f12},
|
||||||
];
|
];
|
||||||
|
|
||||||
//看广告可以获得的奖励。
|
|
||||||
//weight抽奖权重,singleUse使用一次花费的数量,amount抽中可以获得的数量
|
|
||||||
static const List<Map<String, dynamic>> bonusTable = [
|
|
||||||
{"name": "开发者的祝福", "subtitle": "支持开发者的证明", "description": "(*'v'*)\n开发者由衷地感谢你!", "weight": 10000, "amount": 1, "singleUse": 0},
|
|
||||||
{"name": "记忆晶片", "subtitle": "看上去像平行四边形", "description": "组成记忆空间的基本元素。\n是从哪里掉下来的呢?", "weight": 50, "amount": 1, "singleUse": 0},
|
|
||||||
{"name": "Wishes Flower Part", "subtitle": "为1个人献上祝福", "description": "希望之花的花瓣。在想好为谁祝福后, 点击使用", "weight": 500, "amount": 1, "singleUse": 1},
|
|
||||||
{"name": "Wishes Flower Part", "subtitle": "为1个人献上祝福", "description": "希望之花的花瓣。在想好为谁祝福后, 点击使用", "weight": 100, "amount": 3, "singleUse": 1},
|
|
||||||
{"name": "Wishes Flower", "subtitle": "为3个人献上祝福", "description": "希望之花。在想好为谁祝福后, 点击使用", "weight": 50, "amount": 1, "singleUse": 1},
|
|
||||||
{"name": "Bonus Reward", "subtitle": "会有极好的事情发生", "description": "来自记忆空间的传说。\n使用后一天内必有极好的事情...\n就是你想象的那种事情...\n就会发生。\n不过, 大概只是个传说吧。", "weight": 10, "amount": 0.01, "singleUse": 1},
|
|
||||||
{"name": "Bonus Reward", "subtitle": "会有极好的事情发生", "description": "来自记忆空间的传说。\n使用后一天内必有极好的事情...\n就是你想象的那种事情...\n就会发生。\n不过, 大概只是个传说吧。", "weight": 1, "amount": 0.1, "singleUse": 1},
|
|
||||||
{"name": "Bonus Reward", "subtitle": "会有极好的事情发生", "description": "来自记忆空间的传说。\n使用后一天内必有极好的事情...\n就是你想象的那种事情...\n就会发生。\n不过, 大概只是个传说吧。", "weight": 1, "amount": 1, "singleUse": 1},
|
|
||||||
];
|
|
||||||
|
|
||||||
//某项功能开启需要的广告数。
|
|
||||||
static const Map<String, int> adsRequired = {
|
|
||||||
"closeBannerAds" : 5,
|
|
||||||
"enableTerminalWrite" : 2,
|
|
||||||
"enableTerminalCommands" : 3,
|
|
||||||
"changeTermMaxLines" : 6,
|
|
||||||
"changeFFmpegCommand" : 8,
|
|
||||||
"enableVirgl" : 10,
|
|
||||||
"changeHidpiOpt" : 12,
|
|
||||||
|
|
||||||
"unlockOnce" : 1, //临时解锁需要看的广告数
|
|
||||||
"unlockToday" : 2, //当日解锁需要看的广告数
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const String boot = "\$DATA_DIR/bin/proot -H --change-id=1000:1000 --pwd=/home/tiny --rootfs=\$CONTAINER_DIR --mount=/system --mount=/apex --mount=/sys --kill-on-exit --mount=/storage:/storage --sysvipc -L --link2symlink --mount=/proc:/proc --mount=/dev:/dev --mount=\$CONTAINER_DIR/tmp:/dev/shm --mount=/dev/urandom:/dev/random --mount=/proc/self/fd:/dev/fd --mount=/proc/self/fd/0:/dev/stdin --mount=/proc/self/fd/1:/dev/stdout --mount=/proc/self/fd/2:/dev/stderr --mount=/dev/null:/dev/tty0 --mount=/dev/null:/proc/sys/kernel/cap_last_cap --mount=/storage/self/primary:/media/sd --mount=\$DATA_DIR/share:/home/tiny/公共 --mount=\$DATA_DIR/tiny:/home/tiny/.local/share/tiny --mount=/storage/self/primary/Fonts:/usr/share/fonts/wpsm --mount=/storage/self/primary/AppFiles/Fonts:/usr/share/fonts/yozom --mount=/system/fonts:/usr/share/fonts/androidm --mount=/storage/self/primary/Pictures:/home/tiny/图片 --mount=/storage/self/primary/Music:/home/tiny/音乐 --mount=/storage/self/primary/Movies:/home/tiny/视频 --mount=/storage/self/primary/Download:/home/tiny/下载 --mount=/storage/self/primary/DCIM:/home/tiny/照片 --mount=/storage/self/primary/Documents:/home/tiny/文档 --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.stat:/proc/stat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.version:/proc/version --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/bus:/proc/bus --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/buddyinfo:/proc/buddyinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/cgroups:/proc/cgroups --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/consoles:/proc/consoles --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/crypto:/proc/crypto --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/devices:/proc/devices --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/diskstats:/proc/diskstats --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/execdomains:/proc/execdomains --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/fb:/proc/fb --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/filesystems:/proc/filesystems --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/interrupts:/proc/interrupts --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/iomem:/proc/iomem --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/ioports:/proc/ioports --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kallsyms:/proc/kallsyms --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/keys:/proc/keys --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/key-users:/proc/key-users --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kpageflags:/proc/kpageflags --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/loadavg:/proc/loadavg --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/locks:/proc/locks --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/misc:/proc/misc --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/modules:/proc/modules --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/pagetypeinfo:/proc/pagetypeinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/partitions:/proc/partitions --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/sched_debug:/proc/sched_debug --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/softirqs:/proc/softirqs --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/timer_list:/proc/timer_list --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/uptime:/proc/uptime --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmallocinfo:/proc/vmallocinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmstat:/proc/vmstat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/zoneinfo:/proc/zoneinfo \$EXTRA_MOUNT /usr/bin/env -i HOSTNAME=TINY HOME=/home/tiny USER=tiny TERM=xterm-256color SDL_IM_MODULE=fcitx XMODIFIERS=@im=fcitx QT_IM_MODULE=fcitx GTK_IM_MODULE=fcitx TMOE_CHROOT=false TMOE_PROOT=true TMPDIR=/tmp MOZ_FAKE_NO_SANDBOX=1 DISPLAY=:4 PULSE_SERVER=tcp:127.0.0.1:4718 LANG=zh_CN.UTF-8 SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games \$EXTRA_OPT /bin/bash -l";
|
static const String boot = "\$DATA_DIR/bin/proot -H --change-id=1000:1000 --pwd=/home/tiny --rootfs=\$CONTAINER_DIR --mount=/system --mount=/apex --mount=/sys --kill-on-exit --mount=/storage:/storage --sysvipc -L --link2symlink --mount=/proc:/proc --mount=/dev:/dev --mount=\$CONTAINER_DIR/tmp:/dev/shm --mount=/dev/urandom:/dev/random --mount=/proc/self/fd:/dev/fd --mount=/proc/self/fd/0:/dev/stdin --mount=/proc/self/fd/1:/dev/stdout --mount=/proc/self/fd/2:/dev/stderr --mount=/dev/null:/dev/tty0 --mount=/dev/null:/proc/sys/kernel/cap_last_cap --mount=/storage/self/primary:/media/sd --mount=\$DATA_DIR/share:/home/tiny/公共 --mount=\$DATA_DIR/tiny:/home/tiny/.local/share/tiny --mount=/storage/self/primary/Fonts:/usr/share/fonts/wpsm --mount=/storage/self/primary/AppFiles/Fonts:/usr/share/fonts/yozom --mount=/system/fonts:/usr/share/fonts/androidm --mount=/storage/self/primary/Pictures:/home/tiny/图片 --mount=/storage/self/primary/Music:/home/tiny/音乐 --mount=/storage/self/primary/Movies:/home/tiny/视频 --mount=/storage/self/primary/Download:/home/tiny/下载 --mount=/storage/self/primary/DCIM:/home/tiny/照片 --mount=/storage/self/primary/Documents:/home/tiny/文档 --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.stat:/proc/stat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.version:/proc/version --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/bus:/proc/bus --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/buddyinfo:/proc/buddyinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/cgroups:/proc/cgroups --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/consoles:/proc/consoles --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/crypto:/proc/crypto --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/devices:/proc/devices --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/diskstats:/proc/diskstats --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/execdomains:/proc/execdomains --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/fb:/proc/fb --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/filesystems:/proc/filesystems --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/interrupts:/proc/interrupts --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/iomem:/proc/iomem --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/ioports:/proc/ioports --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kallsyms:/proc/kallsyms --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/keys:/proc/keys --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/key-users:/proc/key-users --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kpageflags:/proc/kpageflags --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/loadavg:/proc/loadavg --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/locks:/proc/locks --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/misc:/proc/misc --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/modules:/proc/modules --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/pagetypeinfo:/proc/pagetypeinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/partitions:/proc/partitions --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/sched_debug:/proc/sched_debug --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/softirqs:/proc/softirqs --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/timer_list:/proc/timer_list --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/uptime:/proc/uptime --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmallocinfo:/proc/vmallocinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmstat:/proc/vmstat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/zoneinfo:/proc/zoneinfo \$EXTRA_MOUNT /usr/bin/env -i HOSTNAME=TINY HOME=/home/tiny USER=tiny TERM=xterm-256color SDL_IM_MODULE=fcitx XMODIFIERS=@im=fcitx QT_IM_MODULE=fcitx GTK_IM_MODULE=fcitx TMOE_CHROOT=false TMOE_PROOT=true TMPDIR=/tmp MOZ_FAKE_NO_SANDBOX=1 DISPLAY=:4 PULSE_SERVER=tcp:127.0.0.1:4718 LANG=zh_CN.UTF-8 SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games \$EXTRA_OPT /bin/bash -l";
|
||||||
|
|
||||||
static final ButtonStyle commandButtonStyle = OutlinedButton.styleFrom(
|
static final ButtonStyle commandButtonStyle = OutlinedButton.styleFrom(
|
||||||
@@ -581,11 +503,9 @@ class G {
|
|||||||
static late BuildContext homePageStateContext;
|
static late BuildContext homePageStateContext;
|
||||||
static late int currentContainer; //目前运行第几个容器
|
static late int currentContainer; //目前运行第几个容器
|
||||||
static late Map<int, TermPty> termPtys; //为容器<int>存放TermPty数据
|
static late Map<int, TermPty> termPtys; //为容器<int>存放TermPty数据
|
||||||
static late AdManager ads; //广告实例
|
|
||||||
static late VirtualKeyboard keyboard; //存储ctrl, shift, alt状态
|
static late VirtualKeyboard keyboard; //存储ctrl, shift, alt状态
|
||||||
static bool maybeCtrlJ = false; //为了区分按下的ctrl+J和enter而准备的变量
|
static bool maybeCtrlJ = false; //为了区分按下的ctrl+J和enter而准备的变量
|
||||||
static ValueNotifier<double> termFontScale = ValueNotifier(1); //终端字体大小,存储为G.prefs的termFontScale
|
static ValueNotifier<double> termFontScale = ValueNotifier(1); //终端字体大小,存储为G.prefs的termFontScale
|
||||||
static int adsWatchedThisTime = 0; //本次启动应用看的广告数
|
|
||||||
static bool isStreamServerStarted = false;
|
static bool isStreamServerStarted = false;
|
||||||
static bool isStreaming = false;
|
static bool isStreaming = false;
|
||||||
//static int? streamingPid;
|
//static int? streamingPid;
|
||||||
@@ -596,7 +516,6 @@ class G {
|
|||||||
//static int? virglPid;
|
//static int? virglPid;
|
||||||
static ValueNotifier<int> pageIndex = ValueNotifier(0); //主界面索引
|
static ValueNotifier<int> pageIndex = ValueNotifier(0); //主界面索引
|
||||||
static ValueNotifier<bool> terminalPageChange = ValueNotifier(true); //更改值,用于刷新小键盘
|
static ValueNotifier<bool> terminalPageChange = ValueNotifier(true); //更改值,用于刷新小键盘
|
||||||
static ValueNotifier<bool> bannerAdsChange = ValueNotifier(true); //更改值,用于刷新banner广告
|
|
||||||
static ValueNotifier<bool> bootTextChange = ValueNotifier(true); //更改值,用于刷新启动命令
|
static ValueNotifier<bool> bootTextChange = ValueNotifier(true); //更改值,用于刷新启动命令
|
||||||
static ValueNotifier<String> updateText = ValueNotifier("小小电脑"); //加载界面的说明文字
|
static ValueNotifier<String> updateText = ValueNotifier("小小电脑"); //加载界面的说明文字
|
||||||
static ValueNotifier<String> helpText = ValueNotifier("""
|
static ValueNotifier<String> helpText = ValueNotifier("""
|
||||||
@@ -658,78 +577,6 @@ class G {
|
|||||||
static late SharedPreferences prefs;
|
static late SharedPreferences prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdManager {
|
|
||||||
|
|
||||||
static Map<String, bool> placements = {
|
|
||||||
interstitialVideoAdPlacementId: false,
|
|
||||||
rewardedVideoAdPlacementId: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void loadAds() {
|
|
||||||
for (var placementId in placements.keys) {
|
|
||||||
loadAd(placementId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadAd(String placementId) {
|
|
||||||
UnityAds.load(
|
|
||||||
placementId: placementId,
|
|
||||||
onComplete: (placementId) {
|
|
||||||
debugPrint('Load Complete $placementId');
|
|
||||||
placements[placementId] = true;
|
|
||||||
},
|
|
||||||
onFailed: (placementId, error, message) => debugPrint('Load Failed $placementId: $error $message'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void showAd(String placementId, Function completeExtra, Function full) {
|
|
||||||
|
|
||||||
if ((Util.getGlobal("adsWatchedToday") as int) >= 5) {
|
|
||||||
full();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
placements[placementId] = false;
|
|
||||||
UnityAds.showVideoAd(
|
|
||||||
placementId: placementId,
|
|
||||||
onComplete: (placementId) async {
|
|
||||||
debugPrint('Video Ad $placementId completed');
|
|
||||||
loadAd(placementId);
|
|
||||||
G.adsWatchedThisTime++;
|
|
||||||
await G.prefs.setInt("adsWatchedTotal", (Util.getGlobal("adsWatchedTotal") as int)+1);
|
|
||||||
await G.prefs.setInt("adsWatchedToday", (Util.getGlobal("adsWatchedToday") as int)+1);
|
|
||||||
completeExtra();
|
|
||||||
},
|
|
||||||
onFailed: (placementId, error, message) {
|
|
||||||
debugPrint('Video Ad $placementId failed: $error $message');
|
|
||||||
loadAd(placementId);
|
|
||||||
},
|
|
||||||
onStart: (placementId) => debugPrint('Video Ad $placementId started'),
|
|
||||||
onClick: (placementId) => debugPrint('Video Ad $placementId click'),
|
|
||||||
onSkipped: (placementId) {
|
|
||||||
debugPrint('Video Ad $placementId skipped');
|
|
||||||
loadAd(placementId);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String get gameId {
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
|
||||||
return '5403132';
|
|
||||||
}
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
|
||||||
return '5403133';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static String bannerAdPlacementId = 'Banner_Android';
|
|
||||||
|
|
||||||
static String interstitialVideoAdPlacementId = 'Interstitial_Android';
|
|
||||||
|
|
||||||
static String rewardedVideoAdPlacementId = 'Rewarded_Android';
|
|
||||||
}
|
|
||||||
|
|
||||||
class Workflow {
|
class Workflow {
|
||||||
|
|
||||||
static Future<void> grantPermissions() async {
|
static Future<void> grantPermissions() async {
|
||||||
@@ -850,7 +697,7 @@ done
|
|||||||
final String currentDate = DateFormat("yyyy-MM-dd").format(DateTime.now());
|
final String currentDate = DateFormat("yyyy-MM-dd").format(DateTime.now());
|
||||||
if (currentDate != (Util.getGlobal("lastDate") as String)) {
|
if (currentDate != (Util.getGlobal("lastDate") as String)) {
|
||||||
await G.prefs.setString("lastDate", currentDate);
|
await G.prefs.setString("lastDate", currentDate);
|
||||||
await G.prefs.setInt("adsWatchedToday", 0);
|
//await G.prefs.setInt("adsWatchedToday", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果没有这个key,说明是初次启动
|
//如果没有这个key,说明是初次启动
|
||||||
@@ -876,29 +723,6 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""";
|
|||||||
|
|
||||||
G.controller = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
G.controller = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
|
|
||||||
//恢复临时开启的功能
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeFFmpegCommand"]!)) {
|
|
||||||
await G.prefs.remove("defaultFFmpegCommand");
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!)) {
|
|
||||||
await G.prefs.remove("defaultHidpiOpt");
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["changeTermMaxLines"]!)) {
|
|
||||||
await G.prefs.setInt("termMaxLines", 4095);
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["closeBannerAds"]!)) {
|
|
||||||
await G.prefs.setBool("isBannerAdsClosed", false);
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["enableTerminalWrite"]!)) {
|
|
||||||
await G.prefs.setBool("isTerminalWriteEnabled", false);
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["enableTerminalCommands"]!)) {
|
|
||||||
await G.prefs.setBool("isTerminalCommandsEnabled", false);
|
|
||||||
}
|
|
||||||
if (Util.shouldWatchAds(D.adsRequired["enableVirgl"]!)) {
|
|
||||||
await G.prefs.setBool("virgl", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置屏幕常亮
|
//设置屏幕常亮
|
||||||
WakelockPlus.toggle(enable: Util.getGlobal("wakelock"));
|
WakelockPlus.toggle(enable: Util.getGlobal("wakelock"));
|
||||||
}
|
}
|
||||||
@@ -909,18 +733,6 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> initAds() async {
|
|
||||||
UnityAds.init(
|
|
||||||
gameId: AdManager.gameId,
|
|
||||||
testMode: false,
|
|
||||||
onComplete: () {
|
|
||||||
debugPrint('Initialization Complete');
|
|
||||||
AdManager.loadAds();
|
|
||||||
},
|
|
||||||
onFailed: (error, message) => debugPrint('Initialization Failed: $error $message'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> setupAudio() async {
|
static Future<void> setupAudio() async {
|
||||||
G.audioPty?.kill();
|
G.audioPty?.kill();
|
||||||
G.audioPty = Pty.start(
|
G.audioPty = Pty.start(
|
||||||
@@ -1044,7 +856,6 @@ clear""");
|
|||||||
static Future<void> workflow() async {
|
static Future<void> workflow() async {
|
||||||
grantPermissions();
|
grantPermissions();
|
||||||
await initData();
|
await initData();
|
||||||
await initAds();
|
|
||||||
await initTerminalForCurrent();
|
await initTerminalForCurrent();
|
||||||
setupAudio();
|
setupAudio();
|
||||||
launchCurrentContainer();
|
launchCurrentContainer();
|
||||||
|
|||||||
@@ -549,14 +549,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
unity_ads_plugin:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: unity_ads_plugin
|
|
||||||
sha256: "93dbf4069199440880f97c2c2604034a41945ae760c0b7883271ae02b75ea4d5"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.16"
|
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ dependencies:
|
|||||||
url_launcher: ^6.2.5
|
url_launcher: ^6.2.5
|
||||||
shared_preferences: ^2.2.2
|
shared_preferences: ^2.2.2
|
||||||
intl: ^0.19.0 #日期字符串转换
|
intl: ^0.19.0 #日期字符串转换
|
||||||
unity_ads_plugin: ^0.3.11
|
|
||||||
clipboard: ^0.1.3
|
clipboard: ^0.1.3
|
||||||
ffmpeg_kit_flutter_full_gpl: ^6.0.3
|
ffmpeg_kit_flutter_full_gpl: ^6.0.3
|
||||||
wakelock_plus: ^1.1.6
|
wakelock_plus: ^1.1.6
|
||||||
|
|||||||
Reference in New Issue
Block a user