mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 16:35:47 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70c2018ddf | ||
|
|
b1895af653 | ||
|
|
62995e0a5d | ||
|
|
5ebbaf7073 | ||
|
|
cb1f4b23ee | ||
|
|
0d2f5f4e91 | ||
|
|
d54d1ef6f3 | ||
|
|
0377aa7b8f | ||
|
|
232afe9929 | ||
|
|
fcb472594d | ||
|
|
aa6d0feed7 | ||
|
|
1ee935105e | ||
|
|
7242c45e38 | ||
|
|
d0a539d6dc |
@@ -50,7 +50,7 @@ android {
|
||||
applicationId "com.fct.tiny"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion 24 //ffmpeg_kit; flutter.minSdkVersion
|
||||
minSdkVersion 27 //proot version //ffmpeg_kit; flutter.minSdkVersion
|
||||
targetSdkVersion 28 //https://github.com/termux/termux-app/issues/1072; native; linker; flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
@@ -119,7 +119,7 @@ dependencies {
|
||||
kapt "androidx.room:room-compiler:$roomVersion"
|
||||
|
||||
|
||||
implementation "com.google.android.material:material:1.7.0"
|
||||
implementation "com.google.android.material:material:1.11.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0"
|
||||
implementation "org.connectbot:sshlib:2.2.23"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<application
|
||||
android:label="小小电脑"
|
||||
android:name="${applicationName}"
|
||||
android:name=".MainApplication"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:theme="@style/App.Theme">
|
||||
@@ -33,6 +33,7 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.example.tiny_computer.Signal9Activity" />
|
||||
<activity-alias
|
||||
android:name="com.gaurav.avnc.UriReceiverActivity"
|
||||
android:targetActivity="com.gaurav.avnc.ui.vnc.IntentReceiverActivity">
|
||||
|
||||
@@ -45,6 +45,10 @@ class MainActivity: FlutterActivity() {
|
||||
startActivity(Intent(this, com.gaurav.avnc.ui.about.AboutActivity::class.java))
|
||||
result.success(0)
|
||||
}
|
||||
"launchSignal9Page" -> {
|
||||
startActivity(Intent(this, Signal9Activity::class.java))
|
||||
result.success(0)
|
||||
}
|
||||
else -> {
|
||||
// 不支持的方法名
|
||||
result.notImplemented()
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.example.tiny_computer
|
||||
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import io.flutter.app.FlutterApplication
|
||||
|
||||
class MainApplication : FlutterApplication() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
DynamicColors.applyToActivitiesIfAvailable(this@MainApplication)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.example.tiny_computer
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
|
||||
class Signal9Activity : AppCompatActivity() {
|
||||
|
||||
private val helperLink = "https://www.vmos.cn/zhushou.htm"
|
||||
private val helperLink2 = "https://b23.tv/WwqOqW6"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val rootLayout = LinearLayout(this).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
gravity = Gravity.CENTER
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(16, 16, 16, 16)
|
||||
setBackgroundColor(Color.parseColor("#4A148C"))
|
||||
}
|
||||
|
||||
val scrollView = ScrollView(this).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
val fullScreen = LinearLayout(this).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setBackgroundColor(Color.parseColor("#4A148C"))
|
||||
}
|
||||
|
||||
val text1 = TextView(this).apply {
|
||||
text = ":(\n发生了什么?"
|
||||
textSize = 32f
|
||||
setTextColor(Color.WHITE)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
}
|
||||
|
||||
val text2 = TextView(this).apply {
|
||||
text = "终端异常退出, 返回错误码9\n此错误通常是高版本安卓系统(12+)限制进程造成的, \n可以使用以下工具修复:"
|
||||
textSize = 16f
|
||||
setTextColor(Color.WHITE)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
setPadding(0, 16, 0, 0)
|
||||
}
|
||||
|
||||
val helperLinkText = TextView(this).apply {
|
||||
text = helperLink
|
||||
textSize = 16f
|
||||
setTextColor(Color.WHITE)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
setPadding(0, 16, 0, 0)
|
||||
setOnClickListener { copyToClipboard(helperLink) }
|
||||
}
|
||||
|
||||
val copyHintText = TextView(this).apply {
|
||||
text = "(复制链接到浏览器查看)"
|
||||
textSize = 16f
|
||||
setTextColor(Color.WHITE)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
setPadding(0, 8, 0, 0)
|
||||
}
|
||||
|
||||
val copyButton = Button(this).apply {
|
||||
text = "复制"
|
||||
textSize = 16f
|
||||
setOnClickListener { copyToClipboard(helperLink) }
|
||||
}
|
||||
|
||||
val tutorialText = TextView(this).apply {
|
||||
text = "如果你的设备版本大于等于安卓14,可以在开发者选项里开启“停止限制子进程”选项即可,无需额外修复。\n\n如果不能解决请参考此教程: "
|
||||
textSize = 16f
|
||||
setTextColor(Color.WHITE)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
setPadding(0, 16, 0, 0)
|
||||
}
|
||||
|
||||
val viewButton = Button(this).apply {
|
||||
text = "查看"
|
||||
textSize = 16f
|
||||
setOnClickListener { copyToClipboard(helperLink2) }
|
||||
}
|
||||
|
||||
rootLayout.addView(text1)
|
||||
rootLayout.addView(text2)
|
||||
rootLayout.addView(helperLinkText)
|
||||
rootLayout.addView(copyHintText)
|
||||
rootLayout.addView(copyButton)
|
||||
rootLayout.addView(tutorialText)
|
||||
rootLayout.addView(viewButton)
|
||||
|
||||
scrollView.addView(rootLayout)
|
||||
fullScreen.addView(scrollView)
|
||||
|
||||
setContentView(fullScreen)
|
||||
}
|
||||
|
||||
private fun copyToClipboard(text: String) {
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Copied Text", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(this, "已复制", Toast.LENGTH_SHORT).show()
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(text))
|
||||
startActivity(this, intent, null)
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,10 @@
|
||||
package com.gaurav.avnc.ui.about
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.example.tiny_computer.R
|
||||
|
||||
/**
|
||||
@@ -23,12 +26,19 @@ class AboutActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(R.layout.activity_about)
|
||||
setSupportActionBar(findViewById(R.id.toolbar))
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.about_main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_host, AboutFragment())
|
||||
|
||||
@@ -12,9 +12,12 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
@@ -26,10 +29,16 @@ class PrefsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreference
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
DeviceAuthPrompt.applyFingerprintDialogFix(supportFragmentManager)
|
||||
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_settings)
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.settings_main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
|
||||
@@ -28,7 +28,7 @@ class AppPreferences(context: Context) {
|
||||
inner class Viewer {
|
||||
val orientation; get() = prefs.getString("viewer_orientation", "landscape")
|
||||
val fullscreen; get() = prefs.getBoolean("fullscreen_display", true)
|
||||
val pipEnabled; get() = prefs.getBoolean("pip_enabled", false)
|
||||
val pipEnabled; get() = prefs.getBoolean("pip_enabled", true)
|
||||
val drawBehindCutout; get() = prefs.getBoolean("viewer_draw_behind_cutout", false)
|
||||
val keepScreenOn; get() = prefs.getBoolean("keep_screen_on", true)
|
||||
val toolbarAlignment; get() = prefs.getString("toolbar_alignment", "start")
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
~ See COPYING.txt for more details.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/about_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/settings_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
@@ -31,29 +31,29 @@
|
||||
Note: Some custom ROMs don't respect/support the splash theme introduced in API 31.
|
||||
On such devices, we still rely on the above mentioned workaround.
|
||||
-->
|
||||
<style name="App.SplashTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar" />
|
||||
<style name="App.SplashTheme" parent="Theme.Material3.DayNight.NoActionBar" />
|
||||
|
||||
<style name="App.SplashTheme.Light" parent="Theme.MaterialComponents.Light.NoActionBar" />
|
||||
<style name="App.SplashTheme.Light" parent="Theme.Material3.Light.NoActionBar" />
|
||||
|
||||
<style name="App.SplashTheme.Dark" parent="Theme.MaterialComponents.NoActionBar" />
|
||||
<style name="App.SplashTheme.Dark" parent="Theme.Material3.Dark.NoActionBar" />
|
||||
|
||||
<!--
|
||||
This base theme is used for configuration-specific styling (e.g. night mode, API 23)
|
||||
-->
|
||||
<style name="App.BaseTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar" />
|
||||
<style name="App.BaseTheme" parent="Theme.Material3.DayNight.NoActionBar" />
|
||||
|
||||
<!--
|
||||
This is the main theme.
|
||||
-->
|
||||
<style name="App.Theme" parent="App.BaseTheme">
|
||||
<item name="appBarLayoutStyle">@style/Widget.MaterialComponents.AppBarLayout.Surface</item>
|
||||
<item name="appBarLayoutStyle">@style/Widget.Material3.AppBarLayout</item>
|
||||
</style>
|
||||
|
||||
<style name="AlertDialog.Dimmed" parent="ThemeOverlay.MaterialComponents.MaterialAlertDialog">
|
||||
<style name="AlertDialog.Dimmed" parent="ThemeOverlay.Material3.MaterialAlertDialog">
|
||||
<item name="android:backgroundDimAmount">.6</item>
|
||||
</style>
|
||||
|
||||
<style name="UrlBar" parent="Widget.MaterialComponents.Toolbar">
|
||||
<style name="UrlBar" parent="Widget.Material3.Toolbar">
|
||||
<item name="android:background">@drawable/bg_urlbar</item>
|
||||
<item name="android:layout_marginStart">@dimen/margin_normal</item>
|
||||
<item name="android:layout_marginEnd">@dimen/margin_normal</item>
|
||||
@@ -138,7 +138,7 @@
|
||||
<item name="android:minWidth">50dp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:background">?attr/selectableItemBackgroundBorderless</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance.MaterialComponents.Body2</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance.Material3.BodyMedium</item>
|
||||
</style>
|
||||
|
||||
<style name="VirtualKey.Compact">
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreference
|
||||
app:defaultValue="false"
|
||||
app:defaultValue="true"
|
||||
app:key="pip_enabled"
|
||||
app:title="@string/pref_enable_pip" />
|
||||
|
||||
|
||||
@@ -23,4 +23,5 @@ plugins {
|
||||
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
|
||||
}
|
||||
|
||||
rootProject.name = "TinyComputer"
|
||||
include ":app"
|
||||
|
||||
Binary file not shown.
@@ -12,26 +12,46 @@ rm -rf $HOME/.local/share/tiny/tmp
|
||||
mkdir $HOME/.local/share/tiny/tmp
|
||||
cd $HOME/.local/share/tiny/tmp
|
||||
|
||||
git clone https://mirror.ghproxy.com/https://github.com/ptitSeb/box86
|
||||
if [ $? -ne 0 ]; then
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '仓库克隆失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
box86_url="https://github.com/ptitSeb/box86"
|
||||
box64_url="https://github.com/ptitSeb/box64"
|
||||
|
||||
git clone https://mirror.ghproxy.com/https://github.com/ptitSeb/box64
|
||||
if [ $? -ne 0 ]; then
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '仓库克隆失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
mirror_sites=(
|
||||
"https://github.moeyy.xyz/"
|
||||
"https://mirror.ghproxy.com/"
|
||||
""
|
||||
)
|
||||
|
||||
for mirror in "${mirror_sites[@]}"; do
|
||||
url="${mirror}${box86_url}"
|
||||
echo "尝试从 $url 下载box86..."
|
||||
git clone "${url}"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "成功下载box86"
|
||||
break
|
||||
fi
|
||||
if [ -z "$mirror" ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '仓库克隆失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
for mirror in "${mirror_sites[@]}"; do
|
||||
url="${mirror}${box64_url}"
|
||||
echo "尝试从 $url 下载box64..."
|
||||
git clone "${url}"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "成功下载box64"
|
||||
break
|
||||
fi
|
||||
if [ -z "$mirror" ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '仓库克隆失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
echo "正在编译box86..."
|
||||
cd box86
|
||||
mkdir build
|
||||
cd build
|
||||
@@ -41,6 +61,7 @@ cd ../..
|
||||
mv box86/build/box86 ../cross
|
||||
mv box86/x86lib ../cross
|
||||
|
||||
echo "正在编译box64..."
|
||||
cd box64
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
@@ -4,27 +4,37 @@ rm -rf $HOME/.local/share/tiny/tmp
|
||||
mkdir $HOME/.local/share/tiny/tmp
|
||||
cd $HOME/.local/share/tiny/tmp
|
||||
|
||||
MIRROR_SITE=https://mirror.ghproxy.com
|
||||
RELEASE_PAGE=https://github.com/doitsujin/dxvk/releases
|
||||
LATEST_DXVK_TAG=$(curl -L $RELEASE_PAGE | grep -oP 'Version \K[^"]*</h2>' | cut -d "<" -f 1 | head -n 1)
|
||||
if [ -z "$LATEST_DXVK_TAG" ]
|
||||
then
|
||||
LATEST_DXVK_TAG="2.3"
|
||||
LATEST_DXVK_TAG="2.4"
|
||||
fi
|
||||
LATEST_DXVK_NAME="dxvk-$LATEST_DXVK_TAG.tar.gz"
|
||||
LATEST_DXVK_LINK="https://github.com/doitsujin/dxvk/releases/download/v$LATEST_DXVK_TAG/$LATEST_DXVK_NAME"
|
||||
|
||||
wget $MIRROR_SITE/$LATEST_DXVK_LINK
|
||||
if [ $? -ne 0 ]; then
|
||||
wget $LATEST_DXVK_LINK
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '下载失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
mirror_sites=(
|
||||
"https://github.moeyy.xyz/"
|
||||
"https://mirror.ghproxy.com/"
|
||||
""
|
||||
)
|
||||
|
||||
wineboot
|
||||
for mirror in "${mirror_sites[@]}"; do
|
||||
url="${mirror}$LATEST_DXVK_LINK"
|
||||
echo "尝试从 $url 下载dxvk..."
|
||||
wget "${url}"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "成功下载dxvk"
|
||||
break
|
||||
fi
|
||||
if [ -z "$mirror" ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '下载失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
wine64 wineboot
|
||||
tar xvf $LATEST_DXVK_NAME
|
||||
mv dxvk-$LATEST_DXVK_TAG/x32/* ~/.wine/drive_c/windows/syswow64
|
||||
mv dxvk-$LATEST_DXVK_TAG/x64/* ~/.wine/drive_c/windows/system32
|
||||
|
||||
@@ -32,7 +32,6 @@ rm -rf $HOME/.local/share/tiny/tmp
|
||||
mkdir $HOME/.local/share/tiny/tmp
|
||||
cd $HOME/.local/share/tiny/tmp
|
||||
|
||||
MIRROR_SITE=https://mirror.ghproxy.com
|
||||
RELEASE_PAGE=https://github.com/Kron4ek/Wine-Builds/releases
|
||||
#LATEST_WINE_TAG=proton-$(curl -L $RELEASE_PAGE | grep -oP 'Proton \K[^"]*</h2>' | cut -d "<" -f 1 | head -n 1) #proton
|
||||
LATEST_WINE_TAG=$(curl -L $RELEASE_PAGE | grep -oP 'Wine \K[^"]*</h2>' | cut -d "<" -f 1 | head -n 1) #vanilla
|
||||
@@ -43,15 +42,26 @@ fi
|
||||
LATEST_WINE_NAME=wine-$LATEST_WINE_TAG-amd64.tar.xz
|
||||
LATEST_WINE_LINK=$RELEASE_PAGE/download/$LATEST_WINE_TAG/$LATEST_WINE_NAME
|
||||
|
||||
wget $MIRROR_SITE/$LATEST_WINE_LINK
|
||||
if [ $? -ne 0 ]; then
|
||||
wget $LATEST_WINE_LINK
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '下载失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
mirror_sites=(
|
||||
"https://github.moeyy.xyz/"
|
||||
"https://mirror.ghproxy.com/"
|
||||
""
|
||||
)
|
||||
|
||||
for mirror in "${mirror_sites[@]}"; do
|
||||
url="${mirror}$LATEST_WINE_LINK"
|
||||
echo "尝试从 $url 下载wine..."
|
||||
wget "${url}"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "成功下载wine"
|
||||
break
|
||||
fi
|
||||
if [ -z "$mirror" ]; then
|
||||
rm -rf $HOME/.local/share/tiny/tmp
|
||||
echo '下载失败...退出安装...'
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
tar xvf $LATEST_WINE_NAME
|
||||
mv wine-$LATEST_WINE_TAG-amd64 ../cross/wine
|
||||
|
||||
393
lib/main.dart
393
lib/main.dart
@@ -39,8 +39,6 @@ import 'package:xterm/xterm.dart';
|
||||
//import 'package:xterm/flutter.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';
|
||||
|
||||
void main() {
|
||||
@@ -117,7 +115,7 @@ class SettingPage extends StatefulWidget {
|
||||
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
@@ -134,21 +132,26 @@ class _SettingPageState extends State<SettingPage> {
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("高级设置"), subtitle: Text("修改后重启生效"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("重置启动命令"), onPressed: () {
|
||||
showDialog(context: context, builder: (context) {
|
||||
return AlertDialog(title: const Text("注意"), content: const Text("是否重置启动命令?"), actions: [
|
||||
TextButton(onPressed:() {
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("取消")),
|
||||
TextButton(onPressed:() async {
|
||||
await Util.setCurrentProp("boot", D.boot);
|
||||
G.bootTextChange.value = !G.bootTextChange.value;
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("是")),
|
||||
]);
|
||||
});
|
||||
}),
|
||||
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: [
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("重置启动命令"), onPressed: () {
|
||||
showDialog(context: context, builder: (context) {
|
||||
return AlertDialog(title: const Text("注意"), content: const Text("是否重置启动命令?"), actions: [
|
||||
TextButton(onPressed:() {
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("取消")),
|
||||
TextButton(onPressed:() async {
|
||||
await Util.setCurrentProp("boot", D.boot);
|
||||
G.bootTextChange.value = !G.bootTextChange.value;
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
}, child: const Text("是")),
|
||||
]);
|
||||
});
|
||||
}),
|
||||
OutlinedButton(style: D.commandButtonStyle, child: const Text("Signal9错误页面"), onPressed: () async {
|
||||
await D.avncChannel.invokeMethod("launchSignal9Page", {});
|
||||
}),
|
||||
]),
|
||||
const SizedBox.square(dimension: 8),
|
||||
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("name"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "容器名称"), onChanged: (value) async {
|
||||
await Util.setCurrentProp("name", value);
|
||||
@@ -201,18 +204,10 @@ class _SettingPageState extends State<SettingPage> {
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[1],
|
||||
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: [
|
||||
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,
|
||||
onTap: () {
|
||||
if (Util.shouldWatchAds(D.adsRequired["changeTermMaxLines"]!)) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("观看六次视频广告永久解锁><"))
|
||||
);
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
return Util.validateBetween(value, 1024, 2147483647, () async {
|
||||
await G.prefs.setInt("termMaxLines", int.parse(value!));
|
||||
@@ -228,43 +223,12 @@ class _SettingPageState extends State<SettingPage> {
|
||||
}
|
||||
),
|
||||
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) {
|
||||
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);
|
||||
setState(() {});
|
||||
},),
|
||||
const SizedBox.square(dimension: 8),
|
||||
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);
|
||||
setState(() {
|
||||
G.terminalPageChange.value = !G.terminalPageChange.value;
|
||||
@@ -326,8 +290,8 @@ class _SettingPageState extends State<SettingPage> {
|
||||
final s = WidgetsBinding.instance.platformDispatcher.views.first.physicalSize;
|
||||
final w0 = max(s.width, s.height);
|
||||
final h0 = min(s.width, s.height);
|
||||
String w = (w0 * 0.6).round().toString();
|
||||
String h = (h0 * 0.6).round().toString();
|
||||
String w = (w0 * 0.75).round().toString();
|
||||
String h = (h0 * 0.75).round().toString();
|
||||
showDialog(context: context, builder: (context) {
|
||||
return AlertDialog(title: const Text("分辨率设置"), content: SingleChildScrollView(child: Column(children: [
|
||||
Text("你的设备屏幕分辨率是${w0.round()}x${h0.round()}"),
|
||||
@@ -380,15 +344,7 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
|
||||
一些软件可能会存在显示问题,或者显示速度变慢。"""),
|
||||
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"]!),
|
||||
onTap: () {
|
||||
if (Util.shouldWatchAds(D.adsRequired["changeHidpiOpt"]!)) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("观看十二次视频广告永久解锁><"))
|
||||
);
|
||||
}
|
||||
},
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultHidpiOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "HiDPI环境变量"),
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultHidpiOpt", value);
|
||||
},
|
||||
@@ -440,15 +396,7 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
}),
|
||||
]),
|
||||
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"]!),
|
||||
onTap: () {
|
||||
if (Util.shouldWatchAds(D.adsRequired["changeFFmpegCommand"]!)) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("观看八次视频广告永久解锁><"))
|
||||
);
|
||||
}
|
||||
},
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultFFmpegCommand") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "ffmpeg推流命令"),
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultFFmpegCommand", value);
|
||||
},
|
||||
@@ -516,14 +464,11 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[5],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("virgl加速"), subtitle: Text("实验性功能"));
|
||||
return const ListTile(title: Text("图形加速"), subtitle: Text("实验性功能"));
|
||||
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
|
||||
const Text("""virgl加速可部分利用设备GPU提升系统图形处理表现,但由于设备差异也可能导致容器系统及软件运行不稳定甚至异常退出。
|
||||
const Text("""图形加速可部分利用设备GPU提升系统图形处理表现,但由于设备差异也可能导致容器系统及软件运行不稳定甚至异常退出。
|
||||
|
||||
请先开启测试按钮启动virgl服务器,如果按钮没有自动关闭说明至少启动没问题;
|
||||
|
||||
不过运行情况依然无法保证。
|
||||
"""),
|
||||
Virgl可为使用OpenGL ES的应用提供加速。"""),
|
||||
const SizedBox.square(dimension: 16),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultVirglCommand") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "virgl服务器参数"),
|
||||
onChanged: (value) async {
|
||||
@@ -531,44 +476,34 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
},
|
||||
),
|
||||
const SizedBox.square(dimension: 8),
|
||||
SwitchListTile(title: const Text("测试"), subtitle: const Text("启动virgl_test_server"), value: G.isVirglServerStarted, onChanged:(value) {
|
||||
switch (value) {
|
||||
case true: {
|
||||
G.virglServerPty = Pty.start("/system/bin/sh");
|
||||
G.virglServerPty.write(const Utf8Encoder().convert("export CONTAINER_DIR=${G.dataPath}/containers/${G.currentContainer}\n${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}\nexit\n"));
|
||||
G.virglServerPty.exitCode.then((value) {
|
||||
G.isVirglServerStarted = false;
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case false: {
|
||||
G.virglServerPty.write(const Utf8Encoder().convert("\x03exit\n"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
G.isVirglServerStarted = value;
|
||||
setState(() {});
|
||||
},),
|
||||
const SizedBox.square(dimension: 16),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultVirglOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "图形环境变量"),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultVirglOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "virgl环境变量"),
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultVirglOpt", value);
|
||||
},
|
||||
),
|
||||
const SizedBox.square(dimension: 8),
|
||||
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;
|
||||
}
|
||||
SwitchListTile(title: const Text("启用Virgl加速"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("virgl") as bool, onChanged:(value) {
|
||||
G.prefs.setBool("virgl", value);
|
||||
setState(() {});
|
||||
},),
|
||||
const SizedBox.square(dimension: 16),
|
||||
const Divider(height: 2, indent: 8, endIndent: 8),
|
||||
const SizedBox.square(dimension: 16),
|
||||
const Text("""搭载Adreno GPU的设备通常可以使用Turnip驱动加速使用Vulkan的软件。配合Zink驱动可实现加速使用OpenGL的软件。
|
||||
|
||||
(也就是搭载不太新也不太旧的骁龙处理器的设备)"""),
|
||||
const SizedBox.square(dimension: 8),
|
||||
TextFormField(maxLines: null, initialValue: Util.getGlobal("defaultTurnipOpt") as String, decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "Turnip环境变量"),
|
||||
onChanged: (value) async {
|
||||
await G.prefs.setString("defaultTurnipOpt", value);
|
||||
},
|
||||
),
|
||||
const SizedBox.square(dimension: 8),
|
||||
SwitchListTile(title: const Text("启用Turnip+Zink驱动"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("turnip") as bool, onChanged:(value) async {
|
||||
G.prefs.setBool("turnip", value);
|
||||
setState(() {});
|
||||
},),
|
||||
const SizedBox.square(dimension: 16),
|
||||
],))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[6],
|
||||
@@ -579,9 +514,9 @@ sed -i -E "s@^(VNC_RESOLUTION)=.*@\\1=${w}x${h}@" \$(command -v startvnc)""");
|
||||
|
||||
运行windows程序需要经过架构和系统两层模拟,不要对运行速度抱有期待。程序崩溃也是常有的。
|
||||
|
||||
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
|
||||
建议将要运行的Windows程序连同程序文件夹移至桌面运行。
|
||||
|
||||
如果不耐烦可以去看个广告消磨时间(bushi)
|
||||
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
|
||||
|
||||
或者寻找该windows软件官方是否提供linux arm64版本。
|
||||
|
||||
@@ -704,35 +639,6 @@ fi""");
|
||||
},),
|
||||
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())
|
||||
],))),
|
||||
],);
|
||||
}
|
||||
}
|
||||
@@ -761,116 +667,26 @@ class _InfoPageState extends State<InfoPage> {
|
||||
elevation: 1,
|
||||
expandedHeaderPadding: const EdgeInsets.all(0),
|
||||
expansionCallback: (panelIndex, isExpanded) {
|
||||
setState(() {
|
||||
_expandState[panelIndex] = isExpanded;
|
||||
});
|
||||
_expandState[panelIndex] = isExpanded;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
|
||||
},
|
||||
children: [
|
||||
ExpansionPanel(
|
||||
headerBuilder: (context, isExpanded) {
|
||||
return const ListTile(title: Text("使用说明"));
|
||||
},
|
||||
body: const Padding(padding: EdgeInsets.all(8), child: Text("""
|
||||
第一次加载大概需要5到10分钟...
|
||||
正常情况下,加载完成后软件会自动跳转到图形界面
|
||||
|
||||
在图形界面时,点击即鼠标左键
|
||||
长按为鼠标右键
|
||||
双指点击弹出键盘
|
||||
双指划动为鼠标滚轮
|
||||
|
||||
在图形界面返回,可以回到终端界面和控制界面
|
||||
你可以在控制界面安装更多软件或者阅读帮助信息
|
||||
|
||||
请不要在安装时退出软件
|
||||
|
||||
如果过了很长时间都没有加载完成
|
||||
可以去设置里看看小小电脑占用空间是不是一直没变
|
||||
如果是说明卡在什么地方了
|
||||
建议清除本软件数据重来一次
|
||||
|
||||
(有一位网友提到过
|
||||
自己无论怎么清软件数据都装不上
|
||||
但在重启手机之后就装上了)
|
||||
|
||||
一些注意事项:
|
||||
此软件以GPL协议免费开源
|
||||
如果是买的就是被骗了, 请举报
|
||||
源代码在这里: https://github.com/Cateners/tiny_computer
|
||||
软件也会第一时间在这里更新
|
||||
请尽可能在这里下载软件, 确保是正版
|
||||
|
||||
常见问题:
|
||||
如果你的系统版本大于等于android 12
|
||||
可能会在使用过程中异常退出(返回错误码9)
|
||||
届时本软件会提供方案指引你修复
|
||||
并不难
|
||||
但是软件没有权限
|
||||
不能帮你修复
|
||||
|
||||
如果你的系统版本大于等于android 13
|
||||
那么很可能一些网页应用如jupyter notebook
|
||||
bilibili客户端等等不可用
|
||||
可以去全局设置开启getifaddrs桥接
|
||||
|
||||
如果你给了存储权限
|
||||
那么通过主目录下的文件夹
|
||||
就可以访问设备存储
|
||||
要访问整个设备存储可以访问sd文件夹
|
||||
此外主文件夹的很多文件夹与设备文件夹绑定
|
||||
比如主文件夹的下载文件夹就是设备的下载文件夹
|
||||
|
||||
如果没有给存储权限
|
||||
文件保存到下载文件夹时可能出现问题
|
||||
(火狐浏览器可能因此无法下载文件)
|
||||
你也可以选择换一个文件夹保存
|
||||
|
||||
如果你想安装其他软件
|
||||
可以使用容器自带的tmoe
|
||||
但并不保证安装了能用哦
|
||||
(事实上, 目前容器里的
|
||||
VSCode、输入法
|
||||
都是用tmoe安装的
|
||||
就连系统本身也是用tmoe安装的)
|
||||
|
||||
也可以在网上搜索
|
||||
"ubuntu安装xxx教程"
|
||||
"linux安装xxx教程"等等
|
||||
本软件也提供一些基本软件安装按钮
|
||||
包括图形处理, 视频剪辑, 科学计算相关的软件
|
||||
稍后你就会看到
|
||||
|
||||
如果你需要更多字体
|
||||
在给了存储权限的情况下
|
||||
直接将字体复制到设备存储的Fonts文件夹即可
|
||||
一些常用的办公字体
|
||||
可以在Windows电脑的C:\\Windows\\Fonts文件夹找到
|
||||
由于可能的版权问题
|
||||
软件不能帮你做
|
||||
|
||||
关于中文输入的问题
|
||||
强烈建议不要使用安卓中文输入法直接输入中文
|
||||
而是使用英文键盘通过容器的输入法(Ctrl+空格切换)输入中文
|
||||
避免丢字错字
|
||||
|
||||
如果你遇到了问题
|
||||
可以去https://github.com/Cateners/tiny_computer/issues/
|
||||
留言反馈
|
||||
|
||||
如果软件里有程序正在正常运行
|
||||
请不要强行关闭本软件
|
||||
否则可能会损坏容器
|
||||
(如dpkg被中断)
|
||||
特别是在安装某些比较大的软件的时候
|
||||
|
||||
感谢使用!
|
||||
|
||||
(顺带一提, 全部解压完大概需要4~5GB空间
|
||||
解压途中占用空间可能更多
|
||||
请确保有足够的空间
|
||||
(这样真的Tiny吗><))
|
||||
|
||||
"""
|
||||
body: Padding(padding: const EdgeInsets.all(8), child: Column(
|
||||
children: [
|
||||
ValueListenableBuilder(valueListenable: G.helpText, builder:(context, value, child) {
|
||||
return Text(value);
|
||||
}),
|
||||
const SizedBox.square(dimension: 16),
|
||||
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: D.faq
|
||||
.asMap().entries.map<Widget>((e) {
|
||||
return OutlinedButton(style: D.commandButtonStyle, child: Text(e.value["q"]!), onPressed: () {
|
||||
G.helpText.value = e.value["a"]!;
|
||||
});
|
||||
}).toList())],
|
||||
)),
|
||||
isExpanded: _expandState[0],
|
||||
),
|
||||
@@ -1248,47 +1064,19 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
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(
|
||||
isExpanded: _expandState[2],
|
||||
headerBuilder: ((context, isExpanded) {
|
||||
return const ListTile(title: Text("隐私政策"));
|
||||
}), body: const Padding(padding: EdgeInsets.all(8), child: Text("""
|
||||
除由Unity提供的广告功能外, 本软件不会收集你的隐私信息。
|
||||
本软件不会收集你的隐私信息。
|
||||
|
||||
当然,你在容器系统内部安装或使用的软件行为(包括通过快捷指令)就不受我控制了,我不对其负责。
|
||||
|
||||
本软件申请的权限用于以下目的:
|
||||
文件相关权限:用于系统访问手机目录;
|
||||
相机和麦克风:用于推流,默认不会开启。
|
||||
|
||||
关于广告获取隐私信息的说明, 在第一次看广告时Unity会向你做出告知。
|
||||
届时你可以选择要向Unity提供哪些信息。
|
||||
"""))),
|
||||
ExpansionPanel(
|
||||
isExpanded: _expandState[3],
|
||||
@@ -1310,36 +1098,7 @@ SOFTWARE.
|
||||
}), body: Column(
|
||||
children: [
|
||||
const Padding(padding: EdgeInsets.all(8), child: Text("""
|
||||
这个软件预计会有一些广告
|
||||
分为横幅广告和视频广告
|
||||
横幅广告在终端和控制页面的顶端出现
|
||||
(但不知道是不是因为代码没写对
|
||||
反正我从没见横幅广告成功加载过)
|
||||
视频广告在需要解锁某些功能时自行观看
|
||||
|
||||
这些功能需要累计完整观看对应数目广告后永久解锁:
|
||||
启用终端: 观看2个广告
|
||||
启用小键盘: 观看3个广告
|
||||
关闭横幅广告: 观看5个广告
|
||||
终端最大行数修改: 观看6个广告
|
||||
推流参数修改: 观看8个广告
|
||||
启用virgl加速: 观看10个广告
|
||||
HiDPI环境变量修改: 观看12个广告
|
||||
|
||||
我设置了每天最多可以看5个广告。
|
||||
只要看满1个广告, 就可以在本次使用期间临时解锁全部功能。
|
||||
只要看满2个广告, 就可以在当日使用期间临时解锁全部功能。
|
||||
|
||||
总之为了良好的体验
|
||||
在图形界面是不会出现广告的
|
||||
这点还请放心
|
||||
|
||||
---注意事项---
|
||||
|
||||
我注意到Unity提供了一些不那么合适的广告
|
||||
一般如果我看到这些广告就在后台直接禁了
|
||||
不过也可能有漏网之鱼
|
||||
可以联系我禁掉
|
||||
如果认为好用的话,可以推荐给其他人用噢!
|
||||
""")),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
@@ -1595,20 +1354,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
appBar: AppBar(
|
||||
title: Text(isLoadingComplete?Util.getCurrentProp("name"):widget.title),
|
||||
),
|
||||
body: isLoadingComplete?Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
ValueListenableBuilder(valueListenable: G.bannerAdsChange, 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) {
|
||||
body: isLoadingComplete?
|
||||
ValueListenableBuilder(valueListenable: G.pageIndex, builder: (context, value, child) {
|
||||
return IndexedStack(index: G.pageIndex.value, children: const [TerminalPage(), Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Scrollbar(child: SingleChildScrollView(restorationId: "control-scroll", child: Column(
|
||||
@@ -1633,7 +1380,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
]
|
||||
)))
|
||||
)]);
|
||||
}))]):const LoadingPage(),
|
||||
}):const LoadingPage(),
|
||||
bottomNavigationBar: ValueListenableBuilder(valueListenable: G.pageIndex, builder:(context, value, child) {
|
||||
return Visibility(visible: isLoadingComplete,
|
||||
// child: BottomNavigationBar(currentIndex: G.pageIndex.value,
|
||||
|
||||
@@ -28,7 +28,6 @@ import 'package:retry/retry.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
import 'package:xterm/xterm.dart';
|
||||
@@ -39,11 +38,8 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
||||
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
|
||||
class Util {
|
||||
|
||||
@@ -77,14 +73,10 @@ class Util {
|
||||
//int defaultAudioPort = 4718: 默认pulseaudio端口(为了避免和其它软件冲突改成4718了,原默认4713)
|
||||
//bool autoLaunchVnc = true: 是否自动启动VNC并跳转
|
||||
//String lastDate: 上次启动软件的日期,yyyy-MM-dd
|
||||
//int adsWatchedToday: 今日视频广告观看数量
|
||||
//int adsWatchedTotal: 视频广告观看数量
|
||||
//bool isBannerAdsClosed = false
|
||||
//bool isTerminalWriteEnabled = false
|
||||
//bool isTerminalCommandsEnabled = false
|
||||
//int termMaxLines = 4095 终端最大行数
|
||||
//double termFontScale = 1 终端字体大小
|
||||
//int vip = 0 用户等级,vip免广告,你要改吗?(ToT)
|
||||
//bool isStickyKey = true 终端ctrl, shift, alt键是否粘滞
|
||||
//String defaultFFmpegCommand 默认推流命令
|
||||
//String defaultVirglCommand 默认virgl参数
|
||||
@@ -103,8 +95,6 @@ class Util {
|
||||
//String[] containersInfo: 所有容器信息(json)
|
||||
//{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"}]...]}
|
||||
//String[] adsBonus: 观看广告获取的奖励(json)
|
||||
//{name: "xxx", amount: xxx}
|
||||
//TODO: 这么写还是不对劲,有空改成类试试?
|
||||
static dynamic getGlobal(String key) {
|
||||
bool b = G.prefs.containsKey(key);
|
||||
@@ -113,14 +103,10 @@ class Util {
|
||||
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 "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 "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;}(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);
|
||||
@@ -128,15 +114,16 @@ class Util {
|
||||
case "isBoxEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "isWineEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "virgl" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
|
||||
case "turnip" : 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;}(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 -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");
|
||||
case "defaultTurnipOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("MESA_LOADER_DRIVER_OVERRIDE=zink VK_ICD_FILENAMES=/home/tiny/.local/share/tiny/extra/freedreno_icd.aarch64.json TU_DEBUG=noconform MESA_VK_WSI_DEBUG=sw");
|
||||
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 "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
|
||||
static String? validateBetween(String? value, int min, int max, Function opr) {
|
||||
if (value == null || value.isEmpty) {
|
||||
@@ -322,45 +272,7 @@ class TermPty {
|
||||
}
|
||||
//Signal 9 hint
|
||||
if (code == -9) {
|
||||
Navigator.push(G.homePageStateContext, MaterialPageRoute(builder: (context) {
|
||||
const TextStyle ts = TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.normal);
|
||||
const String helperLink = "https://www.vmos.cn/zhushou.htm";
|
||||
const String helperLink2 = "https://b23.tv/WwqOqW6";
|
||||
return Scaffold(backgroundColor: Colors.deepPurple,
|
||||
body: Center(
|
||||
child: Scrollbar(child:
|
||||
SingleChildScrollView(
|
||||
child: Column(children: [
|
||||
const Text(":(\n发生了什么?", textScaler: TextScaler.linear(2), style: ts, textAlign: TextAlign.center,),
|
||||
const Text("终端异常退出, 返回错误码9\n此错误通常是高版本安卓系统(12+)限制进程造成的, \n可以使用以下工具修复:", style: ts, textAlign: TextAlign.center),
|
||||
const SelectableText(helperLink, style: ts, textAlign: TextAlign.center),
|
||||
const Text("(复制链接到浏览器查看)", style: ts, textAlign: TextAlign.center),
|
||||
OutlinedButton(onPressed: () {
|
||||
FlutterClipboard.copy(helperLink).then(( value ) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: const Text("已复制"), action: SnackBarAction(label: "跳转", onPressed: () {
|
||||
launchUrl(Uri.parse(helperLink), mode: LaunchMode.externalApplication);
|
||||
},))
|
||||
);
|
||||
});
|
||||
}, 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))
|
||||
]),
|
||||
)
|
||||
)
|
||||
));
|
||||
}));
|
||||
D.avncChannel.invokeMethod("launchSignal9Page", {});
|
||||
}
|
||||
});
|
||||
terminal.onOutput = (data) {
|
||||
@@ -386,8 +298,82 @@ class TermPty {
|
||||
|
||||
//default values
|
||||
class D {
|
||||
|
||||
//帮助信息
|
||||
static const faq = [
|
||||
{"q":"安卓12及以上注意事项:错误码9", "a":"""如果你的系统版本大于等于android 12
|
||||
可能会在使用过程中异常退出(返回错误码9)
|
||||
届时本软件会提供方案指引你修复
|
||||
并不难
|
||||
但是软件没有权限
|
||||
不能帮你修复
|
||||
|
||||
你也可以在高级设置里手动前往错误页面"""},
|
||||
{"q":"安卓13注意事项", "a":"""如果你的系统版本大于等于android 13
|
||||
那么很可能一些网页应用如jupyter notebook
|
||||
bilibili客户端等等不可用
|
||||
可以去全局设置开启getifaddrs桥接"""},
|
||||
{"q":"用一会就断掉", "a":"""这应该是出现了错误9的情况
|
||||
下次出现此情况时
|
||||
按设备的返回键(或用返回手势)
|
||||
应该能看到软件提供的修复引导"""},
|
||||
{"q":"如何访问设备文件?", "a":"""如果你给了存储权限
|
||||
那么通过主目录下的文件夹
|
||||
就可以访问设备存储
|
||||
要访问整个设备存储可以访问sd文件夹
|
||||
此外主文件夹的很多文件夹与设备文件夹绑定
|
||||
比如主文件夹的下载文件夹就是设备的下载文件夹"""},
|
||||
{"q":"如何访问SD卡文件?", "a":"""首先用其他文件管理器查看SD卡路径
|
||||
(通常为/storage/xxxx...)
|
||||
然后把该地址输入到小小电脑的文件管理器回车即可
|
||||
|
||||
注意不要只输/storage
|
||||
或者从/storage文件夹点进去
|
||||
那样是没有权限的"""},
|
||||
{"q":"自带的火狐浏览器无法下载文件", "a":"""检查是否授予小小电脑存储权限
|
||||
|
||||
火狐下载的文件会保存在设备的下载文件夹
|
||||
如果不想授予存储权限也可在火狐的设置里更改下载文件夹"""},
|
||||
{"q":"安装更多软件?", "a":"""本软件的初衷是作为PC应用引擎的平替
|
||||
所以我不会提供安装除WPS等软件外的帮助
|
||||
另外你需要一些Linux系统使用经验
|
||||
|
||||
如果你想安装其他软件
|
||||
可以使用容器自带的tmoe
|
||||
但并不保证安装了能用哦
|
||||
(事实上, 目前容器里的
|
||||
VSCode、输入法
|
||||
都是用tmoe安装的
|
||||
就连系统本身也是用tmoe安装的)
|
||||
|
||||
也可以在网上搜索
|
||||
"ubuntu安装xxx教程"
|
||||
"linux安装xxx教程"等等
|
||||
|
||||
要注意容器环境和完整Linux有不同
|
||||
你可能需要做一些修补工作
|
||||
比如基于Electron的软件通常需要添加--no-sandbox参数才能使用"""},
|
||||
{"q":"WPS没有常用字体?", "a":"""如果你需要更多字体
|
||||
在给了存储权限的情况下
|
||||
直接将字体复制到设备存储的Fonts文件夹即可
|
||||
一些常用的办公字体
|
||||
可以在Windows电脑的C:\\Windows\\Fonts文件夹找到
|
||||
由于可能的版权问题
|
||||
软件不能帮你做"""},
|
||||
{"q":"中文输入法?", "a":"""关于中文输入的问题
|
||||
强烈建议不要使用安卓中文输入法直接输入中文
|
||||
而是使用英文键盘通过容器的输入法(Ctrl+空格切换)输入中文
|
||||
避免丢字错字"""},
|
||||
{"q":"镜像正在同步", "a":"""偶尔会出现这种情况
|
||||
一段时间后就会同步完成
|
||||
|
||||
请几个小时后再试一次"""},
|
||||
{"q":"找不到sys/cdefs.h", "a":"""点击上面无法编译C语言程序的快捷指令"""},
|
||||
{"q":"安装box86/box64/wine很慢", "a":"""请尝试使用魔法"""},
|
||||
];
|
||||
|
||||
//默认快捷指令
|
||||
static const commands = [{"name":"检查更新并升级", "command":"sudo apt update && sudo apt upgrade -y"},
|
||||
static const commands = [{"name":"检查更新并升级", "command":"sudo dpkg --configure -a && sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo localedef -c -i zh_CN -f UTF-8 zh_CN.UTF-8"},
|
||||
{"name":"查看系统信息", "command":"neofetch -L && neofetch --off"},
|
||||
{"name":"清屏", "command":"clear"},
|
||||
{"name":"中断任务", "command":"\x03"},
|
||||
@@ -397,9 +383,8 @@ 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":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
|
||||
{"name":"安装WPS", "command":r"""cat << 'EOF' | sh && sudo dpkg --configure -a && sudo apt update && sudo apt install -y /tmp/wps.deb
|
||||
wget https://mirrors.sdu.edu.cn/spark-store-repository/aarch64-store/office/wps-office/wps-office_11.1.0.11720_arm64.deb -O /tmp/wps.deb
|
||||
EOF
|
||||
rm /tmp/wps.deb"""},
|
||||
{"name":"卸载WPS", "command":"sudo apt autoremove --purge -y wps-office"},
|
||||
@@ -409,12 +394,11 @@ rm /tmp/wps.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 '(?<=armDownloadUrl":\\{"deb":")[^"]+') -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.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":"安装UOS微信", "command":"wget https://home-store-packages.uniontech.com/appstore/pool/appstore/c/com.tencent.wechat/com.tencent.wechat_1.0.0.241_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 && ln -sf /opt/apps/com.tencent.wechat/entries/applications/com.tencent.wechat.desktop /usr/share/applications/com.tencent.wechat.desktop && ln -sf /opt/apps/com.tencent.wechat/entries/icons/hicolor /usr/share/icons/wechat && sed -i 's#/usr/bin/wechat#/opt/apps/com.tencent.wechat/files/wechat --no-sandbox#g' /usr/share/applications/com.tencent.wechat.desktop && echo '该微信为UOS特供版,只有账号实名且在UOS系统上运行时可用。在使用前请前往全局设置开启UOS伪装。\n如果你使用微信只是为了传输文件,那么可以考虑使用支持SAF的文件管理器(如:质感文件),直接访问小小电脑所有文件。'; rm /tmp/wechat.deb"},
|
||||
{"name":"卸载UOS微信", "command":"sudo apt autoremove --purge -y com.tencent.wechat deepin-elf-verify && rm /usr/share/applications/com.tencent.wechat.desktop && rm /usr/share/icons/wechat"},
|
||||
{"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 libglut3.12 libglu1-mesa && 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"},
|
||||
{"name":"修复系统语言到中文", "command":"sudo localedef -c -i zh_CN -f UTF-8 zh_CN.UTF-8 #重启生效"},
|
||||
{"name":"启用回收站", "command":"sudo apt update && sudo apt install -y gvfs && echo '安装完成, 重启软件即可使用回收站。'"},
|
||||
{"name":"拉流测试", "command":"ffplay rtsp://127.0.0.1:8554/stream &"},
|
||||
{"name":"关机", "command":"stopvnc\nexit\nexit"},
|
||||
@@ -461,35 +445,7 @@ rm /tmp/wps.deb"""},
|
||||
{"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 --mount=/data --kill-on-exit --mount=/storage --sysvipc -L --link2symlink --mount=/proc --mount=/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(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
@@ -518,24 +474,70 @@ class G {
|
||||
static late BuildContext homePageStateContext;
|
||||
static late int currentContainer; //目前运行第几个容器
|
||||
static late Map<int, TermPty> termPtys; //为容器<int>存放TermPty数据
|
||||
static late AdManager ads; //广告实例
|
||||
static late VirtualKeyboard keyboard; //存储ctrl, shift, alt状态
|
||||
static bool maybeCtrlJ = false; //为了区分按下的ctrl+J和enter而准备的变量
|
||||
static ValueNotifier<double> termFontScale = ValueNotifier(1); //终端字体大小,存储为G.prefs的termFontScale
|
||||
static int adsWatchedThisTime = 0; //本次启动应用看的广告数
|
||||
static bool isStreamServerStarted = false;
|
||||
static bool isStreaming = false;
|
||||
//static int? streamingPid;
|
||||
static String streamingOutput = "";
|
||||
static late Pty streamServerPty;
|
||||
static bool isVirglServerStarted = false;
|
||||
static late Pty virglServerPty;
|
||||
//static int? virglPid;
|
||||
static ValueNotifier<int> pageIndex = ValueNotifier(0); //主界面索引
|
||||
static ValueNotifier<bool> terminalPageChange = ValueNotifier(true); //更改值,用于刷新小键盘
|
||||
static ValueNotifier<bool> bannerAdsChange = ValueNotifier(true); //更改值,用于刷新banner广告
|
||||
static ValueNotifier<bool> bootTextChange = ValueNotifier(true); //更改值,用于刷新启动命令
|
||||
static ValueNotifier<String> updateText = ValueNotifier("小小电脑"); //加载界面的说明文字
|
||||
static ValueNotifier<String> helpText = ValueNotifier("""
|
||||
第一次加载大概需要5到10分钟...
|
||||
正常情况下,加载完成后软件会自动跳转到图形界面
|
||||
|
||||
在图形界面时,点击即鼠标左键
|
||||
长按为鼠标右键
|
||||
双指点击弹出键盘
|
||||
双指划动为鼠标滚轮
|
||||
|
||||
!!!在图形界面返回,可以回到终端界面和控制界面!!!
|
||||
你可以在控制界面安装更多软件或者阅读帮助信息
|
||||
|
||||
请不要在安装时退出软件
|
||||
|
||||
如果过了很长时间都没有加载完成
|
||||
可以去设置里看看小小电脑占用空间是不是一直没变
|
||||
如果是说明卡在什么地方了
|
||||
建议清除本软件数据重来一次
|
||||
|
||||
(有一位网友提到过
|
||||
自己无论怎么清软件数据都装不上
|
||||
但在重启手机之后就装上了)
|
||||
|
||||
一些注意事项:
|
||||
此软件以GPL协议免费开源
|
||||
如果是买的就是被骗了, 请举报
|
||||
源代码在这里: https://github.com/Cateners/tiny_computer
|
||||
软件也会第一时间在这里更新
|
||||
请尽可能在这里下载软件, 确保是正版
|
||||
|
||||
如果你遇到了问题
|
||||
可以去https://github.com/Cateners/tiny_computer/issues/
|
||||
留言反馈
|
||||
|
||||
如果软件里有程序正在正常运行
|
||||
请不要强行关闭本软件
|
||||
否则可能会损坏容器
|
||||
(如dpkg被中断)
|
||||
特别是在安装WPS的时候
|
||||
可能以为卡20%了
|
||||
其实耐心等待就好
|
||||
|
||||
感谢使用!
|
||||
|
||||
(顺带一提, 全部解压完大概需要4~5GB空间
|
||||
解压途中占用空间可能更多
|
||||
请确保有足够的空间
|
||||
(这样真的Tiny吗><))
|
||||
|
||||
常见问题:"""); //帮助页的说明文字
|
||||
static String postCommand = ""; //第一次进入容器时额外运行的命令
|
||||
|
||||
static bool wasBoxEnabled = false; //本次启动时是否启用了box86/64
|
||||
static bool wasWineEnabled = false; //本次启动时是否启用了wine
|
||||
@@ -544,78 +546,6 @@ class G {
|
||||
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 {
|
||||
|
||||
static Future<void> grantPermissions() async {
|
||||
@@ -736,12 +666,19 @@ done
|
||||
final String currentDate = DateFormat("yyyy-MM-dd").format(DateTime.now());
|
||||
if (currentDate != (Util.getGlobal("lastDate") as String)) {
|
||||
await G.prefs.setString("lastDate", currentDate);
|
||||
await G.prefs.setInt("adsWatchedToday", 0);
|
||||
//await G.prefs.setInt("adsWatchedToday", 0);
|
||||
}
|
||||
|
||||
//如果没有这个key,说明是初次启动
|
||||
if (!G.prefs.containsKey("defaultContainer")) {
|
||||
await initForFirstTime();
|
||||
//根据用户的屏幕调整分辨率
|
||||
final s = WidgetsBinding.instance.platformDispatcher.views.first.physicalSize;
|
||||
final String w = (max(s.width, s.height) * 0.75).round().toString();
|
||||
final String h = (min(s.width, s.height) * 0.75).round().toString();
|
||||
G.postCommand = """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)""";
|
||||
await G.prefs.setBool("getifaddrsBridge", (await DeviceInfoPlugin().androidInfo).version.sdkInt >= 31);
|
||||
}
|
||||
G.currentContainer = Util.getGlobal("defaultContainer") as int;
|
||||
|
||||
@@ -756,29 +693,6 @@ done
|
||||
|
||||
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"));
|
||||
}
|
||||
@@ -789,18 +703,6 @@ done
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
G.audioPty?.kill();
|
||||
G.audioPty = Pty.start(
|
||||
@@ -841,6 +743,9 @@ export CONTAINER_DIR=\$DATA_DIR/containers/${G.currentContainer}
|
||||
${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}""");
|
||||
extraOpt += "${Util.getGlobal("defaultVirglOpt")} ";
|
||||
}
|
||||
if (Util.getGlobal("turnip")) {
|
||||
extraOpt += "${Util.getGlobal("defaultTurnipOpt")} ";
|
||||
}
|
||||
if (Util.getGlobal("isBoxEnabled")) {
|
||||
G.wasBoxEnabled = true;
|
||||
extraMount += "--x86=/home/tiny/.local/bin/box86 --x64=/home/tiny/.local/bin/box64 ";
|
||||
@@ -875,6 +780,7 @@ export PROOT_TMP_DIR=\$DATA_DIR/proot_tmp
|
||||
export PROOT_LOADER=\$DATA_DIR/libexec/proot/loader
|
||||
export PROOT_LOADER_32=\$DATA_DIR/libexec/proot/loader32
|
||||
${Util.getCurrentProp("boot")}
|
||||
${G.postCommand}
|
||||
${(Util.getGlobal("autoLaunchVnc") as bool)?Util.getCurrentProp("vnc"):""}
|
||||
clear""");
|
||||
}
|
||||
@@ -923,7 +829,6 @@ clear""");
|
||||
static Future<void> workflow() async {
|
||||
grantPermissions();
|
||||
await initData();
|
||||
await initAds();
|
||||
await initTerminalForCurrent();
|
||||
setupAudio();
|
||||
launchCurrentContainer();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import device_info_plus
|
||||
import dynamic_color
|
||||
import ffmpeg_kit_flutter_full_gpl
|
||||
import network_info_plus
|
||||
@@ -15,6 +16,7 @@ import url_launcher_macos
|
||||
import wakelock_plus
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||
FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin"))
|
||||
NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin"))
|
||||
|
||||
220
pubspec.lock
220
pubspec.lock
@@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.5.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -73,6 +73,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.1.2"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
dynamic_color:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -138,10 +154,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
|
||||
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "4.0.0"
|
||||
flutter_pty:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -172,10 +188,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -192,46 +208,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.0"
|
||||
version: "10.0.4"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.3"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.1"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
||||
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "4.0.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -252,26 +260,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.12.0"
|
||||
network_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: network_info_plus
|
||||
sha256: "4601b815b1c6a46d84839f65cd774a7d999738471d910fae00d813e9e98b04e1"
|
||||
sha256: "0754302af09e58a60c7cd6800029d00e03c68f289a19fd9df31941ab91da8903"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0+1"
|
||||
version: "6.0.0"
|
||||
network_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_platform_interface
|
||||
sha256: "881f5029c5edaf19c616c201d3d8b366c5b1384afd5c1da5a49e4345de82fb8b"
|
||||
sha256: b7f35f4a7baef511159e524499f3c15464a49faa5ec10e92ee0bce265e664906
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "2.0.1"
|
||||
nm:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -284,18 +292,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017"
|
||||
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "8.0.2"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
|
||||
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -308,26 +316,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
||||
sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.9"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -348,50 +356,50 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.3.0"
|
||||
permission_handler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44"
|
||||
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.3.0"
|
||||
version: "11.3.1"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
|
||||
sha256: eaf2a1ec4472775451e88ca6a7b86559ef2f1d1ed903942ed135e38ea0097dca
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.0.5"
|
||||
version: "12.0.8"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b
|
||||
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.4.0"
|
||||
version: "9.4.5"
|
||||
permission_handler_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_html
|
||||
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
|
||||
sha256: "6cac773d389e045a8d4f85418d07ad58ef9e42a56e063629ce14c4c26344de24"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
version: "0.1.2"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78"
|
||||
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "4.2.2"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -412,10 +420,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -444,58 +452,58 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
||||
sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.3.1"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
||||
sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.3.1"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||
sha256: "776786cff96324851b656777648f36ac772d88bc4c669acff97b7fce5de3c849"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
version: "2.5.1"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
|
||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.4.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -545,10 +553,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
version: "0.7.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -557,54 +565,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
unity_ads_plugin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: unity_ads_plugin
|
||||
sha256: "636858a9ff573bf3477cb1d2f2663d73ef360790fa7638acbd9631adb24c76c9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.11"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
|
||||
sha256: "94d8ad05f44c6d4e2ffe5567ab4d741b82d62e3c8e288cc1fcea45965edf47c9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.3.8"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
version: "6.3.1"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
version: "3.2.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -617,18 +617,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d"
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
version: "3.1.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -641,26 +641,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
version: "14.2.1"
|
||||
wakelock_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: wakelock_plus
|
||||
sha256: "26ebc8b5e0037c15e2a1b661dcec8a475cb7205befcce8a33f545ae8c86b367c"
|
||||
sha256: "4fa83a128b4127619e385f686b4f080a5d2de46cff8e8c94eccac5fcf76550e5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
version: "1.2.7"
|
||||
wakelock_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_plus_platform_interface
|
||||
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
|
||||
sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -673,18 +673,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932"
|
||||
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "4.8.0"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0"
|
||||
sha256: c66651fba15f9d7ddd31daec42da8d6bce46c85610a7127e3ebcb39a4395c3c9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.15.0"
|
||||
version: "3.16.6"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -697,18 +697,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86"
|
||||
sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.12.0"
|
||||
version: "3.14.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||
sha256: "015002c060f1ae9f41a818f2d5640389cc05283e368be19dc8d77cecb43c40c9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.0"
|
||||
version: "5.5.3"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32_registry
|
||||
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -742,5 +750,5 @@ packages:
|
||||
source: hosted
|
||||
version: "0.0.6"
|
||||
sdks:
|
||||
dart: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
dart: ">=3.4.0 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
||||
22
pubspec.yaml
22
pubspec.yaml
@@ -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
|
||||
# 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.
|
||||
version: 1.0.15+11
|
||||
version: 1.0.17+13
|
||||
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
@@ -33,20 +33,20 @@ dependencies:
|
||||
xterm: ^4.0.0
|
||||
flutter_pty: ^0.4.0
|
||||
path_provider: ^2.1.2
|
||||
webview_flutter: ^4.7.0
|
||||
permission_handler: ^11.3.0
|
||||
http: ^1.2.1
|
||||
webview_flutter: ^4.8.0
|
||||
permission_handler: ^11.3.1
|
||||
http: ^1.2.2
|
||||
retry: ^3.1.2
|
||||
url_launcher: ^6.2.5
|
||||
shared_preferences: ^2.2.2
|
||||
url_launcher: ^6.3.0
|
||||
shared_preferences: ^2.2.3
|
||||
intl: ^0.19.0 #日期字符串转换
|
||||
unity_ads_plugin: ^0.3.11
|
||||
clipboard: ^0.1.3
|
||||
ffmpeg_kit_flutter_full_gpl: ^6.0.3
|
||||
wakelock_plus: ^1.1.6
|
||||
dynamic_color: ^1.6.9
|
||||
wakelock_plus: ^1.2.7
|
||||
dynamic_color: ^1.7.0
|
||||
flutter_speed_dial: ^7.0.0
|
||||
network_info_plus: ^4.1.0+1
|
||||
network_info_plus: ^6.0.0
|
||||
device_info_plus: ^10.1.2
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
@@ -61,7 +61,7 @@ dev_dependencies:
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^3.0.1
|
||||
flutter_lints: ^4.0.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
Reference in New Issue
Block a user