Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f64f690a0a | |||
| b0c4a7e05a | |||
| 0a44f56c2f | |||
| 527c8176e4 | |||
| a54219b781 | |||
| 84cf16c3bf | |||
| becf6779f7 | |||
| d61b2aa907 | |||
| 534c08c70a | |||
| bc3e6f514a | |||
| 2469b9ff83 | |||
| f3abdff971 | |||
| af1b71f929 | |||
| 4146f260ac | |||
| 7c5200f838 | |||
| 17d6856f58 | |||
| 2ba164a05c | |||
| ecd02b8885 | |||
| 08caef28ab | |||
| b587da0b9a | |||
| 0f7748a1df | |||
| 2a2159eb8a | |||
| 866de7a49e | |||
| c49be0b2e7 | |||
| 00155e3619 | |||
| 6a9b6bc3a8 | |||
| e7b7751fbb | |||
| 66f6ef6cec | |||
| 1d149bfa19 | |||
| 707f7adbeb | |||
| b9f73f0d0f | |||
| 2f191a2c41 | |||
| 47f3f1f55d | |||
| 9399dbe051 | |||
| a044ca8189 | |||
| 67e06fd017 | |||
| 629e0cb456 | |||
| 4135f02885 | |||
| 6149ff55ab | |||
| 7722e5fa70 | |||
| dafb6aba1b | |||
| 3e967d7bed | |||
| c75207f8e1 | |||
| 3871dc8677 | |||
| 72dc9b238f | |||
| edf158028e | |||
| e21b59b9b1 | |||
| 4c10a53229 | |||
| e61bb39fc5 | |||
| 8f86f3ea61 | |||
| d57f7c024b | |||
| aec3601f2a | |||
| b54d8bd0c5 | |||
| 89a772152b | |||
| ed411fc284 | |||
| b7b0457685 | |||
| bdd458a64f | |||
| 93d86df411 | |||
| a0cef76ae6 | |||
| b40252d958 | |||
| 01b311fb24 |
61
.gitea/workflows/build.yml
Normal file
61
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: Build
|
||||||
|
run-name: ${{ gitea.actor }} build 🚀
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Set Up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: amyu/setup-android@v5
|
||||||
|
with:
|
||||||
|
cache-disabled: true
|
||||||
|
|
||||||
|
- name: Grant execute permissions
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew
|
||||||
|
chmod +x ./script/release-uploader
|
||||||
|
|
||||||
|
- name: Download AAR manually
|
||||||
|
run: |
|
||||||
|
FILE="app/libs/firefly-go.aar"
|
||||||
|
URL="https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/media/branch/master/app/libs/firefly-go.aar"
|
||||||
|
echo "📥 Downloading $FILE from $URL"
|
||||||
|
curl -L -o "$FILE" "$URL"
|
||||||
|
|
||||||
|
- name: Build signed release APK
|
||||||
|
env:
|
||||||
|
KEYSTORE_PATH: ${{ github.workspace }}/KeyStore.jks
|
||||||
|
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||||
|
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||||
|
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
./gradlew assembleRelease \
|
||||||
|
-Pandroid.injected.signing.store.file=$KEYSTORE_PATH \
|
||||||
|
-Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD \
|
||||||
|
-Pandroid.injected.signing.key.alias=$KEY_ALIAS \
|
||||||
|
-Pandroid.injected.signing.key.password=$KEY_PASSWORD
|
||||||
|
|
||||||
|
- name: Find and rename release APK
|
||||||
|
run: |
|
||||||
|
APK_FILE=$(ls app/build/outputs/apk/release/*.apk | head -n 1)
|
||||||
|
echo "Found APK: $APK_FILE"
|
||||||
|
mv "$APK_FILE" app/build/outputs/apk/release/firefly_go_android.apk
|
||||||
|
|
||||||
|
- name: Upload release
|
||||||
|
env:
|
||||||
|
REPO_TOKEN: ${{ secrets.REPO_TOKEN }}
|
||||||
|
run: script/release-uploader -token=$REPO_TOKEN -release-url="https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Android/releases" -files="app/build/outputs/apk/release/firefly_go_android.apk"
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
|
.history/
|
||||||
2
.idea/.name
generated
2
.idea/.name
generated
@@ -1 +1 @@
|
|||||||
FireflyPsAndorid
|
FireflyGoAndroid
|
||||||
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="21" />
|
<bytecodeTargetLevel target="17" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
13
.idea/deviceManager.xml
generated
Normal file
13
.idea/deviceManager.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DeviceTable">
|
||||||
|
<option name="columnSorters">
|
||||||
|
<list>
|
||||||
|
<ColumnSorterState>
|
||||||
|
<option name="column" value="Name" />
|
||||||
|
<option name="order" value="ASCENDING" />
|
||||||
|
</ColumnSorterState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@@ -15,5 +15,6 @@
|
|||||||
</option>
|
</option>
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="parallelModelFetch" value="true" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
BIN
KeyStore.jks
BIN
KeyStore.jks
Binary file not shown.
@@ -1,60 +1,99 @@
|
|||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
}
|
}
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(17)
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.example.fireflypsandorid"
|
namespace = "com.example.firefly_go_android"
|
||||||
compileSdk = 35
|
compileSdk = 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.example.fireflypsandorid"
|
applicationId = "com.kain344.firefly_go_android"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
//noinspection OldTargetApi
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = true
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro"
|
"proguard-rules.pro"
|
||||||
)
|
)
|
||||||
|
ndk {
|
||||||
|
abiFilters.addAll(listOf("arm64-v8a"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = "11"
|
|
||||||
}
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose = true
|
compose = true
|
||||||
|
viewBinding = true
|
||||||
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.5.0"
|
||||||
|
}
|
||||||
|
buildToolsVersion = "36.0.0"
|
||||||
|
ndkVersion = "27.2.12479018"
|
||||||
|
dependenciesInfo {
|
||||||
|
includeInApk = false
|
||||||
|
includeInBundle = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx.v293)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose.v1101)
|
||||||
implementation(platform(libs.androidx.compose.bom))
|
// Compose UI
|
||||||
implementation(libs.androidx.ui)
|
implementation(libs.ui)
|
||||||
implementation(libs.androidx.ui.graphics)
|
implementation(libs.ui.graphics)
|
||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.ui.tooling.preview)
|
||||||
implementation(libs.androidx.material3)
|
|
||||||
|
// Foundation & Animation
|
||||||
|
implementation(libs.androidx.foundation)
|
||||||
|
implementation(libs.androidx.animation)
|
||||||
|
implementation(libs.androidx.animation.core)
|
||||||
|
|
||||||
|
// Material & Material3
|
||||||
|
implementation(libs.androidx.material)
|
||||||
|
implementation(libs.androidx.material.icons.extended)
|
||||||
|
implementation(libs.material3)
|
||||||
|
implementation(libs.androidx.material3.window.size.class1)
|
||||||
|
|
||||||
|
// Auto updater library
|
||||||
|
implementation(libs.autoupdater)
|
||||||
|
|
||||||
|
// Unit Test
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
// Android Instrumentation Test
|
||||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
androidTestImplementation(libs.androidx.junit.v130)
|
||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.espresso.core.v370)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
androidTestImplementation(libs.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
|
||||||
implementation(files("../library/firefly-go.aar"))
|
// Debug
|
||||||
|
debugImplementation(libs.ui.tooling)
|
||||||
|
debugImplementation(libs.ui.test.manifest)
|
||||||
|
|
||||||
|
// Local AAR library
|
||||||
|
implementation(files("libs/firefly-go.aar"))
|
||||||
|
|
||||||
|
implementation(libs.slf4j.android)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
app/libs/firefly-go-sources.jar
Normal file
BIN
app/libs/firefly-go-sources.jar
Normal file
Binary file not shown.
BIN
app/libs/firefly-go.aar
LFS
Normal file
BIN
app/libs/firefly-go.aar
LFS
Normal file
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
package com.example.fireflypsandorid
|
package com.example.firefly_go_android
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
@@ -3,13 +3,11 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
<uses-permission android:name="android.permission.READ_LOGS"/>
|
||||||
tools:ignore="ScopedStorage" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -20,23 +18,33 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:theme="@style/Theme.FireflyPsAndorid"
|
android:theme="@style/Theme.FireflyGoAndroid"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:theme="@style/Theme.FireflyGoAndroid">
|
||||||
android:theme="@style/Theme.FireflyPsAndorid">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".GolangServerService"
|
android:name=".GolangServerService"
|
||||||
android:foregroundServiceType="dataSync" />
|
android:foregroundServiceType="dataSync"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package com.example.firefly_go_android
|
||||||
|
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import libandroid.Libandroid
|
||||||
|
|
||||||
|
class GolangServerService : Service() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CHANNEL_ID = "GolangServerChannel"
|
||||||
|
const val NOTIFICATION_ID = 1
|
||||||
|
private const val TAG = "GolangServerService"
|
||||||
|
var isRunning by mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var wakeLock: PowerManager.WakeLock? = null
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
createNotificationChannel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
if (isRunning) {
|
||||||
|
Log.d(TAG, "❗ Server is already running")
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
isRunning = true
|
||||||
|
Log.d(TAG, "onStartCommand called")
|
||||||
|
|
||||||
|
val notificationIntent = Intent(this, MainActivity::class.java)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
notificationIntent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
val largeIcon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
|
||||||
|
|
||||||
|
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
.setSmallIcon(R.mipmap.ic_launcher_round)
|
||||||
|
.setLargeIcon(largeIcon)
|
||||||
|
.setContentTitle("FireflyGO Server")
|
||||||
|
.setContentText("Server is running...")
|
||||||
|
.setColor(ContextCompat.getColor(this, R.color.teal_700))
|
||||||
|
.setOngoing(true)
|
||||||
|
.setOnlyAlertOnce(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
|
.setShowWhen(false)
|
||||||
|
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
startForeground(NOTIFICATION_ID, notification)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
|
||||||
|
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GolangServer::WakeLock")
|
||||||
|
wakeLock?.acquire(10*60*1000L)
|
||||||
|
Log.d(TAG, "✅ WakeLock acquired")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ WakeLock failed", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
try {
|
||||||
|
val appDataPath = intent?.getStringExtra("appDataPath")
|
||||||
|
if (appDataPath != null) {
|
||||||
|
Libandroid.setPathDataLocal(appDataPath)
|
||||||
|
Log.d(TAG, "✅ Set path data: $appDataPath")
|
||||||
|
} else {
|
||||||
|
isRunning = false
|
||||||
|
Log.e(TAG, "❌ appDataPath not received in intent")
|
||||||
|
stopSelf()
|
||||||
|
return@Thread
|
||||||
|
}
|
||||||
|
|
||||||
|
Libandroid.setServerRunning(true)
|
||||||
|
isRunning = true
|
||||||
|
Log.d(TAG, "✅ Server started")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
isRunning = false
|
||||||
|
Log.e(TAG, "❌ Error starting server", e)
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "onDestroy called")
|
||||||
|
|
||||||
|
// 1. Tắt server
|
||||||
|
try {
|
||||||
|
val result = Libandroid.setServerRunning(false)
|
||||||
|
isRunning = false
|
||||||
|
Log.d(TAG, "Server shutdown result: $result")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Error shutting down server", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
wakeLock?.let {
|
||||||
|
if (it.isHeld) {
|
||||||
|
it.release()
|
||||||
|
Log.d(TAG, "✅ WakeLock released")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ Failed to release WakeLock", e)
|
||||||
|
}
|
||||||
|
isRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? = null
|
||||||
|
|
||||||
|
private fun createNotificationChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val channel = NotificationChannel(
|
||||||
|
CHANNEL_ID,
|
||||||
|
"Golang Server Channel",
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
|
description = "Channel for running Golang backend in foreground"
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
manager.createNotificationChannel(channel)
|
||||||
|
Log.d(TAG, "✅ Notification channel created")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
904
app/src/main/java/com/example/firefly_go_android/MainActivity.kt
Normal file
904
app/src/main/java/com/example/firefly_go_android/MainActivity.kt
Normal file
@@ -0,0 +1,904 @@
|
|||||||
|
package com.example.firefly_go_android
|
||||||
|
|
||||||
|
import AutoUpdaterManager
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.autoupdater.UpdateFeatures
|
||||||
|
import com.example.firefly_go_android.ui.theme.FireflyPsAndoridTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.*
|
||||||
|
import androidx.compose.animation.*
|
||||||
|
import androidx.compose.animation.core.*
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.BugReport
|
||||||
|
import androidx.compose.material.icons.filled.CloudDownload
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
|
import androidx.compose.material.icons.filled.PlayCircleFilled
|
||||||
|
import androidx.compose.material.icons.filled.RestartAlt
|
||||||
|
import androidx.compose.material.icons.filled.Stop
|
||||||
|
import androidx.compose.material.icons.filled.StopCircle
|
||||||
|
import androidx.compose.material.icons.rounded.AutoAwesome
|
||||||
|
import androidx.compose.material.icons.rounded.CheckCircle
|
||||||
|
import androidx.compose.material.icons.rounded.Download
|
||||||
|
import androidx.compose.material.icons.rounded.InstallMobile
|
||||||
|
import androidx.compose.material.icons.rounded.SystemUpdate
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.scale
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Shadow
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import org.json.JSONObject
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
|
||||||
|
data class AppVersion(
|
||||||
|
val latestVersion: String,
|
||||||
|
val changelog: String,
|
||||||
|
val apkUrl: String
|
||||||
|
)
|
||||||
|
|
||||||
|
class MainActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val appDataPath = filesDir.absolutePath
|
||||||
|
val dataDir = File("$appDataPath/data")
|
||||||
|
dataDir.mkdirs()
|
||||||
|
|
||||||
|
copyRawToFile(this, dataDir, "data-in-game.json", R.raw.data_in_game_json)
|
||||||
|
copyRawToFile(this, dataDir, "freesr-data.json", R.raw.freesr_data_json)
|
||||||
|
copyRawToFile(this, dataDir, "version.json", R.raw.version_json)
|
||||||
|
|
||||||
|
val jsonString = resources.openRawResource(R.raw.app_version_json).use { input ->
|
||||||
|
input.bufferedReader().use { it.readText() }
|
||||||
|
}
|
||||||
|
|
||||||
|
val jsonObject = JSONObject(jsonString)
|
||||||
|
val latestVersion = jsonObject.getString("latest_version")
|
||||||
|
val changelog = jsonObject.getString("changelog")
|
||||||
|
val apkUrl = jsonObject.getString("apk_url")
|
||||||
|
|
||||||
|
val appVersion = AppVersion(latestVersion, changelog, apkUrl)
|
||||||
|
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContent {
|
||||||
|
FireflyPsAndoridTheme {
|
||||||
|
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
ServerControlScreen(appDataPath, dataDir, appVersion, Modifier.padding(innerPadding))
|
||||||
|
AutoUpdateDialog(onDismiss = {}, appVersion, dataDir, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyRawToFile(context: Context, targetDir: File, fileName: String, resId: Int, override: Boolean = false) {
|
||||||
|
val outFile = File(targetDir, fileName)
|
||||||
|
if (!outFile.exists() || override) {
|
||||||
|
try {
|
||||||
|
context.resources.openRawResource(resId).use { input ->
|
||||||
|
FileOutputStream(outFile).use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i("FileCopy", "${if (override) "✅ Overridden" else "✅ Copied"} $fileName to ${outFile.absolutePath}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("FileCopy", "❌ Failed to copy $fileName: ${e.message}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i("FileCopy", "ℹ️ $fileName already exists at ${outFile.absolutePath}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFile(targetDir: File, fileName: String): Boolean {
|
||||||
|
val file = File(targetDir, fileName)
|
||||||
|
return if (file.exists()) {
|
||||||
|
try {
|
||||||
|
if (file.delete()) {
|
||||||
|
Log.i("FileRemove", "🗑️ Removed $fileName from ${file.absolutePath}")
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
Log.e("FileRemove", "❌ Failed to remove $fileName from ${file.absolutePath}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("FileRemove", "❌ Error removing $fileName: ${e.message}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i("FileRemove", "ℹ️ $fileName does not exist in ${targetDir.absolutePath}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ImplicitSamInstance")
|
||||||
|
@Composable
|
||||||
|
fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersion, modifier: Modifier = Modifier) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val isRunning = GolangServerService.isRunning
|
||||||
|
|
||||||
|
var showResetDialog by remember { mutableStateOf(false) }
|
||||||
|
var showUpdateDialog by remember { mutableStateOf(false) }
|
||||||
|
var showLogs by remember { mutableStateOf(false) }
|
||||||
|
Box(
|
||||||
|
modifier = modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
// Background image
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.background),
|
||||||
|
contentDescription = "Background",
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Black.copy(alpha = 0.3f))
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(24.dp),
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// Title
|
||||||
|
Text(
|
||||||
|
text = "Firefly GO for Android",
|
||||||
|
fontSize = 26.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(top = 24.dp),
|
||||||
|
color = Color.White,
|
||||||
|
style = TextStyle(
|
||||||
|
shadow = Shadow(
|
||||||
|
color = Color.Black,
|
||||||
|
offset = Offset(2f, 2f),
|
||||||
|
blurRadius = 4f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server status with icon
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isRunning) Icons.Default.PlayCircleFilled else Icons.Default.StopCircle,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (isRunning) Color(0xFF4CAF50) else Color.Gray,
|
||||||
|
modifier = Modifier.size(40.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = if (isRunning) "Server is running" else "Server is stopped",
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
style = TextStyle(
|
||||||
|
shadow = Shadow(
|
||||||
|
color = Color.Black,
|
||||||
|
offset = Offset(1f, 1f),
|
||||||
|
blurRadius = 2f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(200.dp))
|
||||||
|
// Toggle button
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
try {
|
||||||
|
if (!isRunning) {
|
||||||
|
val intent = Intent(context, GolangServerService::class.java)
|
||||||
|
intent.putExtra("appDataPath", appDataPath)
|
||||||
|
context.startService(intent)
|
||||||
|
} else {
|
||||||
|
context.stopService(Intent(context, GolangServerService::class.java))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = if (isRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
|
||||||
|
contentColor = Color.White
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(0.8f)
|
||||||
|
.height(50.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isRunning) Icons.Default.Stop else Icons.Default.PlayArrow,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = if (isRunning) "Stop Server" else "Start Server",
|
||||||
|
fontSize = 20.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
// Widget icons row
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(32.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Check Update widget
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable { showUpdateDialog = true }
|
||||||
|
.background(
|
||||||
|
Color.White.copy(alpha = 0.8f),
|
||||||
|
RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.padding(12.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.CloudDownload,
|
||||||
|
contentDescription = "Check Update",
|
||||||
|
tint = Color.Gray,
|
||||||
|
modifier = Modifier.size(32.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Update",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = Color.Black,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Data widget
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable { showResetDialog = true }
|
||||||
|
.background(
|
||||||
|
Color.White.copy(alpha = 0.8f),
|
||||||
|
RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.padding(12.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.RestartAlt,
|
||||||
|
contentDescription = "Reset Data",
|
||||||
|
tint = Color.Gray,
|
||||||
|
modifier = Modifier.size(32.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Reset",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = Color.Black,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logcat (Lynx) widget
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
showLogs = true // mở popup log
|
||||||
|
}
|
||||||
|
.background(
|
||||||
|
Color.White.copy(alpha = 0.8f),
|
||||||
|
RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.padding(12.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.BugReport,
|
||||||
|
contentDescription = "Open Logcat",
|
||||||
|
tint = Color.Gray,
|
||||||
|
modifier = Modifier.size(32.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Logs",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = Color.Black,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(75.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showLogs) {
|
||||||
|
LogPopup(onDismiss = { showLogs = false })
|
||||||
|
}
|
||||||
|
// Reset Data Confirmation Dialog
|
||||||
|
if (showResetDialog) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showResetDialog = false },
|
||||||
|
title = {
|
||||||
|
Text(text = "Reset Data")
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(text = "Do you want reset all data? This action can not rollback.")
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
showResetDialog = false
|
||||||
|
try {
|
||||||
|
copyRawToFile(context, dataDir, "data-in-game.json", R.raw.data_in_game_json, true)
|
||||||
|
copyRawToFile(context, dataDir, "freesr-data.json", R.raw.freesr_data_json, true)
|
||||||
|
copyRawToFile(context, dataDir, "version.json", R.raw.version_json, true)
|
||||||
|
Toast.makeText(context, "Data has been reset successfully", Toast.LENGTH_SHORT).show()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "Reset failed: ${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Yes", color = Color(0xFFFF0606))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = { showResetDialog = false }
|
||||||
|
) {
|
||||||
|
Text("No")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto Update Dialog
|
||||||
|
if (showUpdateDialog) {
|
||||||
|
AutoUpdateDialog(
|
||||||
|
onDismiss = { showUpdateDialog = false },
|
||||||
|
appVersion,
|
||||||
|
dataDir
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseGoLogLine(line: String): String? {
|
||||||
|
val regex = Regex(""".*GoLog\s*:?\s*(.*)""")
|
||||||
|
val match = regex.find(line)
|
||||||
|
val content = match?.groupValues?.getOrNull(1)?.trim()
|
||||||
|
|
||||||
|
return if (content.isNullOrBlank()) null else content
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun parseAnsi(text: String, defaultColor: Color): AnnotatedString {
|
||||||
|
val regex = Regex("\u001B\\[(\\d+)(;\\d+)*m")
|
||||||
|
val builder = buildAnnotatedString {
|
||||||
|
var lastIndex = 0
|
||||||
|
var currentColor = defaultColor
|
||||||
|
|
||||||
|
for (match in regex.findAll(text)) {
|
||||||
|
val start = match.range.first
|
||||||
|
|
||||||
|
// 1. Thêm phần text TRƯỚC mã ANSI với màu HIỆN TẠI
|
||||||
|
val before = text.substring(lastIndex, start)
|
||||||
|
if (before.isNotEmpty()) {
|
||||||
|
withStyle(SpanStyle(color = currentColor)) {
|
||||||
|
append(before)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Lấy mã code (ví dụ 31, 36, hoặc 0)
|
||||||
|
val code = try {
|
||||||
|
match.groupValues[1].toInt()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
currentColor = when (code) {
|
||||||
|
0 -> defaultColor
|
||||||
|
30 -> Color.Black
|
||||||
|
31 -> Color.Red
|
||||||
|
32 -> Color(0xFF00C853) // Green
|
||||||
|
33 -> Color(0xFFFFD600) // Yellow
|
||||||
|
34 -> Color(0xFF2962FF) // Blue
|
||||||
|
35 -> Color(0xFFD500F9) // Magenta
|
||||||
|
36 -> Color(0xFF00B8D4) // Cyan
|
||||||
|
37 -> Color.White
|
||||||
|
else -> currentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = match.range.last + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIndex < text.length) {
|
||||||
|
val remain = text.substring(lastIndex)
|
||||||
|
if (remain.isNotEmpty()) {
|
||||||
|
withStyle(SpanStyle(color = currentColor)) {
|
||||||
|
append(remain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LogPopup(
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
var logs by remember { mutableStateOf(listOf<String>()) }
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val process = Runtime.getRuntime().exec("logcat -s GoLog")
|
||||||
|
val reader = BufferedReader(InputStreamReader(process.inputStream))
|
||||||
|
|
||||||
|
var line: String?
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
val clean = parseGoLogLine(line!!)
|
||||||
|
if (!clean.isNullOrBlank()) {
|
||||||
|
logs = (logs + clean).takeLast(200)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logs = logs + "Error reading logcat: ${e.message}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LaunchedEffect(logs.size) {
|
||||||
|
if (logs.isNotEmpty()) {
|
||||||
|
listState.animateScrollToItem(logs.size - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultTextColor = LocalContentColor.current
|
||||||
|
|
||||||
|
Dialog(onDismissRequest = { onDismiss() }) {
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
tonalElevation = 8.dp,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.fillMaxHeight(0.7f)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
|
Text(
|
||||||
|
text = "GoLog Output",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
LazyColumn(state = listState, modifier = Modifier.weight(1f)) {
|
||||||
|
items(logs.size) { index ->
|
||||||
|
Text(
|
||||||
|
text = parseAnsi(logs[index], defaultTextColor),
|
||||||
|
fontSize = 12.sp,
|
||||||
|
|
||||||
|
// 2. DÙNG FONT MONOSPACE
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
|
||||||
|
// 3. (Tuỳ chọn) Giảm chiều cao dòng để logo liền mạch
|
||||||
|
lineHeight = 14.sp,
|
||||||
|
|
||||||
|
modifier = Modifier.padding(vertical = 2.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Button(
|
||||||
|
onClick = { onDismiss() },
|
||||||
|
modifier = Modifier.align(Alignment.End)
|
||||||
|
) {
|
||||||
|
Text("Close")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AutoUpdateDialog(
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
appVersion: AppVersion,
|
||||||
|
dataDir: File,
|
||||||
|
isFirstOpen: Boolean = false
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val autoUpdaterManager = AutoUpdaterManager(context)
|
||||||
|
var update by remember { mutableStateOf<UpdateFeatures?>(null) }
|
||||||
|
var progress by remember { mutableIntStateOf(0) }
|
||||||
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
|
var isDownloading by remember { mutableStateOf(false) }
|
||||||
|
var downloadComplete by remember { mutableStateOf(false) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val progressAnimation by animateFloatAsState(
|
||||||
|
targetValue = progress / 100f,
|
||||||
|
animationSpec = tween(300, easing = FastOutSlowInEasing),
|
||||||
|
label = "progress"
|
||||||
|
)
|
||||||
|
|
||||||
|
val scaleAnimation by animateFloatAsState(
|
||||||
|
targetValue = if (showDialog) 1f else 0.8f,
|
||||||
|
animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy),
|
||||||
|
label = "scale"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check for update
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
val result = withContext(Dispatchers.IO) {
|
||||||
|
autoUpdaterManager.checkForUpdate(
|
||||||
|
JSONfileURL = "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Andoid/raw/branch/master/app/src/main/res/raw/app_version_json.json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasUpdate = result != null && appVersion.latestVersion != result.latestversion
|
||||||
|
|
||||||
|
update = if (hasUpdate) result else null
|
||||||
|
|
||||||
|
showDialog = if (isFirstOpen) {
|
||||||
|
hasUpdate
|
||||||
|
} else {
|
||||||
|
result != null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Download progress
|
||||||
|
LaunchedEffect(progress) {
|
||||||
|
if (progress >= 100 && isDownloading) {
|
||||||
|
downloadComplete = true
|
||||||
|
|
||||||
|
removeFile(dataDir, "data-in-game.json" )
|
||||||
|
removeFile(dataDir, "freesr-data.json")
|
||||||
|
removeFile(dataDir, "version.json")
|
||||||
|
delay(500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showDialog) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
if (!isDownloading) showDialog = false
|
||||||
|
onDismiss()
|
||||||
|
},
|
||||||
|
properties = DialogProperties(
|
||||||
|
dismissOnBackPress = !isDownloading,
|
||||||
|
dismissOnClickOutside = !isDownloading
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
.scale(scaleAnimation)
|
||||||
|
.animateContentSize(),
|
||||||
|
shape = RoundedCornerShape(24.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(24.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// Header icon
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(72.dp)
|
||||||
|
.background(
|
||||||
|
MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
CircleShape
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (update != null) Icons.Rounded.SystemUpdate
|
||||||
|
else Icons.Rounded.CheckCircle,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(36.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Title
|
||||||
|
Text(
|
||||||
|
text = if (update != null) "Update Available" else "No Update Available",
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
|
if (update != null) {
|
||||||
|
VersionInfoSection(update!!)
|
||||||
|
ChangelogSection(update!!)
|
||||||
|
DownloadProgressSection(
|
||||||
|
isDownloading = isDownloading,
|
||||||
|
downloadComplete = downloadComplete,
|
||||||
|
progress = progressAnimation
|
||||||
|
)
|
||||||
|
ActionButtons(
|
||||||
|
isDownloading = isDownloading,
|
||||||
|
downloadComplete = downloadComplete,
|
||||||
|
onDownloadClick = {
|
||||||
|
isDownloading = true
|
||||||
|
coroutineScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
autoUpdaterManager.downloadapk(
|
||||||
|
context,
|
||||||
|
update!!.apk_url,
|
||||||
|
"FireflyGO_${update!!.latestversion}.apk"
|
||||||
|
) { prog -> progress = prog }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismiss = { showDialog = false; onDismiss() }
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Your app is up to date",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = { showDialog = false; onDismiss() },
|
||||||
|
modifier = Modifier.wrapContentWidth(),
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onPrimary
|
||||||
|
),
|
||||||
|
contentPadding = PaddingValues(horizontal = 32.dp, vertical = 12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "OK",
|
||||||
|
style = MaterialTheme.typography.labelMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version info card
|
||||||
|
@Composable
|
||||||
|
fun VersionInfoSection(update: UpdateFeatures) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.7f)
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Latest Version",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "v${update.latestversion}",
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changelog section
|
||||||
|
@Composable
|
||||||
|
fun ChangelogSection(update: UpdateFeatures) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Rounded.AutoAwesome,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "What's New",
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = update.changelog,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
lineHeight = 20.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress section
|
||||||
|
@Composable
|
||||||
|
fun DownloadProgressSection(
|
||||||
|
isDownloading: Boolean,
|
||||||
|
downloadComplete: Boolean,
|
||||||
|
progress: Float
|
||||||
|
) {
|
||||||
|
if (!isDownloading && !downloadComplete) return
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = if (downloadComplete) "Installation Ready" else "Downloading...",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${(progress*100).toInt()}%",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = { progress },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(8.dp)
|
||||||
|
.clip(RoundedCornerShape(4.dp)),
|
||||||
|
color = if (downloadComplete) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.primary,
|
||||||
|
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action buttons
|
||||||
|
@Composable
|
||||||
|
fun ActionButtons(
|
||||||
|
isDownloading: Boolean,
|
||||||
|
downloadComplete: Boolean,
|
||||||
|
onDownloadClick: () -> Unit,
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = if (!isDownloading && !downloadComplete) Arrangement.spacedBy(12.dp) else Arrangement.Center
|
||||||
|
) {
|
||||||
|
if (!downloadComplete) {
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = onDismiss,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
enabled = !isDownloading,
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Later", style = MaterialTheme.typography.labelLarge)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = onDownloadClick,
|
||||||
|
modifier = if (downloadComplete) Modifier.widthIn(min = 160.dp) else Modifier.weight(1f),
|
||||||
|
enabled = !isDownloading || downloadComplete,
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = if (downloadComplete) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
|
||||||
|
when {
|
||||||
|
downloadComplete -> {
|
||||||
|
Icon(Icons.Rounded.InstallMobile, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text("Install Now", style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.Medium)
|
||||||
|
}
|
||||||
|
isDownloading -> {
|
||||||
|
CircularProgressIndicator(modifier = Modifier.size(24.dp), color = MaterialTheme.colorScheme.onPrimary)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Rounded.Download,
|
||||||
|
contentDescription = "Download",
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.fireflypsandorid.ui.theme
|
package com.example.firefly_go_android.ui.theme
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.example.fireflypsandorid.ui.theme
|
package com.example.firefly_go_android.ui.theme
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.fireflypsandorid.ui.theme
|
package com.example.firefly_go_android.ui.theme
|
||||||
|
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
package com.example.fireflypsandorid
|
|
||||||
|
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.Service
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.IBinder
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import libandroid.Libandroid
|
|
||||||
|
|
||||||
class GolangServerService : Service() {
|
|
||||||
companion object {
|
|
||||||
const val CHANNEL_ID = "GolangServerChannel"
|
|
||||||
const val NOTIFICATION_ID = 1
|
|
||||||
private const val TAG = "GolangServerService"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
createNotificationChannel()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
||||||
val notificationIntent = Intent(this, MainActivity::class.java)
|
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
|
||||||
this, 0, notificationIntent,
|
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
|
||||||
)
|
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
|
||||||
.setContentTitle("Golang Server")
|
|
||||||
.setContentText("Server đang chạy")
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
startForeground(NOTIFICATION_ID, notification)
|
|
||||||
|
|
||||||
// Chạy server trong thread riêng để tránh ANR
|
|
||||||
Thread {
|
|
||||||
try {
|
|
||||||
val appDataPath = intent?.getStringExtra("appDataPath")
|
|
||||||
|
|
||||||
if (appDataPath != null) {
|
|
||||||
Libandroid.setPathDataLocal(appDataPath)
|
|
||||||
Log.d(TAG, "✅ Set path data: $appDataPath")
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "❌ appDataPath not received in intent")
|
|
||||||
}
|
|
||||||
|
|
||||||
Libandroid.setServerRunning(true)
|
|
||||||
Log.d(TAG, "✅ Server started")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "❌ Error when start server:", e)
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
|
|
||||||
return START_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
try {
|
|
||||||
val result = Libandroid.setServerRunning(false)
|
|
||||||
Log.d(TAG, "Server shutdown result: $result")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error shutting down server", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createNotificationChannel() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val channel = NotificationChannel(
|
|
||||||
CHANNEL_ID,
|
|
||||||
"Golang Server Channel",
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
).apply {
|
|
||||||
description = "Notify Golang backend runing"
|
|
||||||
}
|
|
||||||
|
|
||||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
notificationManager.createNotificationChannel(channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
package com.example.fireflypsandorid
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material3.*
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.*
|
|
||||||
import androidx.compose.ui.graphics.Brush
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import com.example.fireflypsandorid.ui.theme.FireflyPsAndoridTheme
|
|
||||||
import java.io.*
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
|
||||||
private val TAG = "AppInit"
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
val appDataPath = filesDir.absolutePath
|
|
||||||
val dataDir = File("$appDataPath/data")
|
|
||||||
dataDir.mkdirs()
|
|
||||||
|
|
||||||
checkAndCreateFile(dataDir, "data-in-game.json", R.raw.data_in_game_json)
|
|
||||||
checkAndCreateFile(dataDir, "freesr-data.json", R.raw.freesr_data_json)
|
|
||||||
checkAndCreateFile(dataDir, "version.json", R.raw.version_json)
|
|
||||||
|
|
||||||
enableEdgeToEdge()
|
|
||||||
setContent {
|
|
||||||
FireflyPsAndoridTheme {
|
|
||||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
|
||||||
ServerControlScreen(appDataPath, Modifier.padding(innerPadding))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkAndCreateFile(targetDir: File, fileName: String, resId: Int) {
|
|
||||||
val outFile = File(targetDir, fileName)
|
|
||||||
if (!outFile.exists()) {
|
|
||||||
try {
|
|
||||||
resources.openRawResource(resId).use { input ->
|
|
||||||
FileOutputStream(outFile).use { output ->
|
|
||||||
input.copyTo(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.i(TAG, "✅ Copied $fileName to ${outFile.absolutePath}")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "❌ Failed to copy $fileName: ${e.message}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "ℹ️ $fileName already exists at ${outFile.absolutePath}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
|
|
||||||
val context = LocalContext.current
|
|
||||||
var isServerRunning by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val serverImage = if (isServerRunning)
|
|
||||||
painterResource(id = R.drawable.server_running)
|
|
||||||
else
|
|
||||||
painterResource(id = R.drawable.server_stopped)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(24.dp),
|
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
// Title
|
|
||||||
Text(
|
|
||||||
text = "Firefly Ps for Android",
|
|
||||||
fontSize = 26.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 24.dp),
|
|
||||||
color = Color(0xFF4CAF50).copy(alpha = 0.9f) // Lime Green
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
|
|
||||||
// Server status image
|
|
||||||
Image(
|
|
||||||
painter = serverImage,
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(250.dp)
|
|
||||||
.padding(8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
|
|
||||||
// Toggle button
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
try {
|
|
||||||
isServerRunning = !isServerRunning
|
|
||||||
if (isServerRunning) {
|
|
||||||
val intent = Intent(context, GolangServerService::class.java)
|
|
||||||
intent.putExtra("appDataPath", appDataPath)
|
|
||||||
context.startService(intent)
|
|
||||||
} else {
|
|
||||||
context.stopService(Intent(context, GolangServerService::class.java))
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Toast.makeText(context, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFFFF5722),
|
|
||||||
contentColor = Color.White
|
|
||||||
),
|
|
||||||
shape = RoundedCornerShape(12.dp),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth(0.7f)
|
|
||||||
.height(50.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = if (isServerRunning) "Stop Server" else "Start Server",
|
|
||||||
fontSize = 20.sp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
|
|
||||||
// Server status text
|
|
||||||
Text(
|
|
||||||
text = if (isServerRunning) "Server is running" else "Server is stopped",
|
|
||||||
fontSize = 24.sp,
|
|
||||||
color = if (isServerRunning) Color(0xFF4CAF50) else Color.Gray
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
app/src/main/res/drawable/background.jpg
Normal file
BIN
app/src/main/res/drawable/background.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB |
5
app/src/main/res/raw/app_version_json.json
Normal file
5
app/src/main/res/raw/app_version_json.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"latest_version": "3.7.2-01",
|
||||||
|
"changelog": "UPDATE: 3.7.52",
|
||||||
|
"apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/releases/download/3.7.2-01/firefly_go_android.apk"
|
||||||
|
}
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
{
|
{
|
||||||
|
"leader": 1,
|
||||||
"lineups": {
|
"lineups": {
|
||||||
"0": 1310,
|
"0": 1413,
|
||||||
"1": 1410,
|
"1": 1415,
|
||||||
"2": 1409,
|
"2": 1409,
|
||||||
"3": 1407
|
"3": 1407
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"x": -1115,
|
"x": -4030,
|
||||||
"z": -642542,
|
"z": -13006,
|
||||||
"y": -152077,
|
"y": 0,
|
||||||
"rot_y": 195849
|
"rot_y": 270000
|
||||||
},
|
},
|
||||||
"scene": {
|
"scene": {
|
||||||
"plane_id": 10304,
|
"plane_id": 10000,
|
||||||
"floor_id": 10304001,
|
"floor_id": 10000000,
|
||||||
"entry_id": 1030402
|
"entry_id": 100000104
|
||||||
},
|
},
|
||||||
|
"player_outfit": [
|
||||||
|
1001
|
||||||
|
],
|
||||||
"char_path": {
|
"char_path": {
|
||||||
"main": 8008,
|
"main": 8008,
|
||||||
"march_7": 1224
|
"march_7": 1224
|
||||||
@@ -26,37 +30,201 @@
|
|||||||
"1205": 1,
|
"1205": 1,
|
||||||
"1212": 1
|
"1212": 1
|
||||||
},
|
},
|
||||||
"battle": {
|
"challenge": {
|
||||||
"battle_id": 0,
|
"challenge_id": 0,
|
||||||
"skip_half": 0,
|
"skip_half": 0,
|
||||||
"blessings": [],
|
"blessings": [],
|
||||||
"freesr": false,
|
"is_in_challenge": false,
|
||||||
"current_half": 0,
|
"current_stage_id": 30119122,
|
||||||
"path_resonance_id": 0,
|
"path_resonance_id": 0,
|
||||||
"maze_buff": 0,
|
"maze_buff": 0,
|
||||||
"first_lineup": [],
|
"first_lineup": [],
|
||||||
"second_lineup": []
|
"second_lineup": []
|
||||||
},
|
},
|
||||||
|
"challenge_peak": {
|
||||||
|
"current_mode": "Boss",
|
||||||
|
"group_id": 3,
|
||||||
|
"is_in_challenge_peak": false,
|
||||||
|
"challenge_peak_data": {
|
||||||
|
"1": {
|
||||||
|
"checkmate_data": {
|
||||||
|
"challenge_id": 104,
|
||||||
|
"blessing": 3033006,
|
||||||
|
"lineup": [
|
||||||
|
1413,
|
||||||
|
1409,
|
||||||
|
1407,
|
||||||
|
1403
|
||||||
|
],
|
||||||
|
"stage_id": 30501022,
|
||||||
|
"is_hard_mode": true
|
||||||
|
},
|
||||||
|
"knight_data": {
|
||||||
|
"current_challenge_id": 103,
|
||||||
|
"details_data": [
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1222,
|
||||||
|
1225,
|
||||||
|
1310,
|
||||||
|
1303
|
||||||
|
],
|
||||||
|
"stage_id": 30501011,
|
||||||
|
"challenge_id": 101
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1412,
|
||||||
|
1414,
|
||||||
|
1408,
|
||||||
|
1313
|
||||||
|
],
|
||||||
|
"stage_id": 30501012,
|
||||||
|
"challenge_id": 102
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1407,
|
||||||
|
1403,
|
||||||
|
1409,
|
||||||
|
1413
|
||||||
|
],
|
||||||
|
"stage_id": 30501013,
|
||||||
|
"challenge_id": 103
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"checkmate_data": {
|
||||||
|
"challenge_id": 204,
|
||||||
|
"blessing": 3033021,
|
||||||
|
"lineup": [
|
||||||
|
1415,
|
||||||
|
1413,
|
||||||
|
1409,
|
||||||
|
1407
|
||||||
|
],
|
||||||
|
"stage_id": 30502022,
|
||||||
|
"is_hard_mode": true
|
||||||
|
},
|
||||||
|
"knight_data": {
|
||||||
|
"current_challenge_id": 203,
|
||||||
|
"details_data": [
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1302,
|
||||||
|
1309,
|
||||||
|
1410
|
||||||
|
],
|
||||||
|
"stage_id": 30502011,
|
||||||
|
"challenge_id": 201
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1221,
|
||||||
|
1222
|
||||||
|
],
|
||||||
|
"stage_id": 30502012,
|
||||||
|
"challenge_id": 202
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1415,
|
||||||
|
8001,
|
||||||
|
1414,
|
||||||
|
1313
|
||||||
|
],
|
||||||
|
"stage_id": 30502013,
|
||||||
|
"challenge_id": 203
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"checkmate_data": {
|
||||||
|
"challenge_id": 304,
|
||||||
|
"blessing": 3033032,
|
||||||
|
"lineup": [
|
||||||
|
1222,
|
||||||
|
1225,
|
||||||
|
1310,
|
||||||
|
1321
|
||||||
|
],
|
||||||
|
"stage_id": 30503021,
|
||||||
|
"is_hard_mode": false
|
||||||
|
},
|
||||||
|
"knight_data": {
|
||||||
|
"current_challenge_id": 302,
|
||||||
|
"details_data": [
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1003
|
||||||
|
],
|
||||||
|
"stage_id": 30503011,
|
||||||
|
"challenge_id": 301
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
1315
|
||||||
|
],
|
||||||
|
"stage_id": 30503012,
|
||||||
|
"challenge_id": 302
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lineup": [
|
||||||
|
8001
|
||||||
|
],
|
||||||
|
"stage_id": 30503013,
|
||||||
|
"challenge_id": 303
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"theory_craft": {
|
"theory_craft": {
|
||||||
"hp": {
|
"hp": {
|
||||||
"1": 600000,
|
"1": [
|
||||||
"2": 10000000
|
200000,
|
||||||
|
1000000,
|
||||||
|
200000
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
2000000000,
|
||||||
|
2000000000,
|
||||||
|
2000000000
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"cycle_count": 1,
|
"cycle_count": 1,
|
||||||
"log": false,
|
|
||||||
"mode": false
|
"mode": false
|
||||||
},
|
},
|
||||||
"profile_data": {
|
"profile_data": {
|
||||||
"cur_chat_bubble_id": 220008,
|
"cur_chat_bubble_id": 220009,
|
||||||
"cur_phone_theme_id": 221011,
|
"cur_phone_theme_id": 221012,
|
||||||
"cur_phone_case_id": 254001,
|
"cur_phone_case_id": 254001,
|
||||||
"cur_pam_skin_id": 252000,
|
"cur_pam_skin_id": 252000,
|
||||||
"cur_pet_id": 1002,
|
"cur_pet_id": 0,
|
||||||
"cur_avatar_player_icon": 202034,
|
"cur_avatar_player_icon": 202034,
|
||||||
"cur_player_personal_card": 253001
|
"cur_player_personal_card": 253001,
|
||||||
|
"cur_signature": "Firefly GO By Kain",
|
||||||
|
"cur_display_avatar": [
|
||||||
|
1310,
|
||||||
|
1309,
|
||||||
|
1407,
|
||||||
|
1413,
|
||||||
|
1412
|
||||||
|
],
|
||||||
|
"cur_is_display_avatar": true
|
||||||
},
|
},
|
||||||
"skin_data": {
|
"skin_data": {
|
||||||
"1001": 1100101,
|
"1001": 1100101,
|
||||||
"1310": 1131001
|
"1310": 1131001
|
||||||
|
},
|
||||||
|
"extra_setting": {
|
||||||
|
"censorship": false,
|
||||||
|
"cm": false,
|
||||||
|
"first_person": false,
|
||||||
|
"hide_ui": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,260 +1,212 @@
|
|||||||
{
|
{
|
||||||
"CNBETAAndroid3.3.51": {
|
"CNBETAAndroid3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"CNBETAAndroid3.3.52": {
|
"CNBETAAndroid3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"CNBETAAndroid3.3.53": {
|
"CNBETAAndroid3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
|
},
|
||||||
|
"CNBETAAndroid3.6.54": {
|
||||||
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
|
},
|
||||||
|
"CNBETAAndroid3.7.51": {
|
||||||
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
},
|
||||||
"CNBETAAndroid3.3.54": {
|
"CNBETAWin3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"CNBETAAndroid3.3.55": {
|
"CNBETAWin3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"CNBETAAndroid3.4.51": {
|
"CNBETAWin3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
},
|
},
|
||||||
"CNBETAWin3.3.51": {
|
"CNBETAWin3.6.54": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
},
|
},
|
||||||
"CNBETAWin3.3.52": {
|
"CNBETAWin3.7.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
},
|
|
||||||
"CNBETAWin3.3.53": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
},
|
||||||
"CNBETAWin3.3.54": {
|
"CNBETAiOS3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"CNBETAWin3.3.55": {
|
"CNBETAiOS3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"CNBETAWin3.4.51": {
|
"CNBETAiOS3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
},
|
},
|
||||||
"CNBETAiOS3.3.51": {
|
"CNBETAiOS3.6.54": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
},
|
},
|
||||||
"CNBETAiOS3.3.52": {
|
"CNBETAiOS3.7.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
},
|
|
||||||
"CNBETAiOS3.3.53": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
},
|
||||||
"CNBETAiOS3.3.54": {
|
"OSBETAAndroid3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"CNBETAiOS3.3.55": {
|
"OSBETAAndroid3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"CNBETAiOS3.4.51": {
|
"OSBETAAndroid3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
},
|
},
|
||||||
"CNPRODAndroid3.2.0": {
|
"OSBETAAndroid3.6.54": {
|
||||||
"asset_bundle_url": "prod_official_asia",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"lua_url": "client version not match"
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
},
|
},
|
||||||
"CNPRODAndroid3.3.0": {
|
"OSBETAAndroid3.7.51": {
|
||||||
"asset_bundle_url": "prod_official_asia"
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
},
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"CNPRODWin3.2.0": {
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
"asset_bundle_url": "prod_official_asia",
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
"lua_url": "client version not match"
|
|
||||||
},
|
|
||||||
"CNPRODWin3.3.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia"
|
|
||||||
},
|
|
||||||
"CNPRODiOS3.2.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia",
|
|
||||||
"lua_url": "client version not match"
|
|
||||||
},
|
|
||||||
"CNPRODiOS3.3.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia"
|
|
||||||
},
|
|
||||||
"OSBETAAndroid3.3.51": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
|
||||||
},
|
|
||||||
"OSBETAAndroid3.3.52": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
|
||||||
},
|
|
||||||
"OSBETAAndroid3.3.53": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
},
|
||||||
"OSBETAAndroid3.3.54": {
|
"OSBETAWin3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"OSBETAAndroid3.3.55": {
|
"OSBETAWin3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"OSBETAAndroid3.4.51": {
|
"OSBETAWin3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
},
|
},
|
||||||
"OSBETAWin3.3.51": {
|
"OSBETAWin3.6.54": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
},
|
},
|
||||||
"OSBETAWin3.3.52": {
|
"OSBETAWin3.7.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
},
|
|
||||||
"OSBETAWin3.3.53": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
},
|
||||||
"OSBETAWin3.3.54": {
|
"OSBETAiOS3.6.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12066992_f083970b907e_999074cab6dce6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12056690_16bfd67c199f_f3c0367d7b051e",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12114942_e99cbde25134_e63a6b835f17f9",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12103115_ee78155e9867_3626f0948d93e2",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12118783_55113408814f_c874267d04c04a"
|
||||||
},
|
},
|
||||||
"OSBETAWin3.3.55": {
|
"OSBETAiOS3.6.52": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12150127_00d6d096d968_cd76a04beb7ba6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12178965_e246796e0bb6_05bcce36cd648b",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12150614_5279f6d8029a_bdecff99d2d817",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12164593_8e3fba5163df_b2b6fc46de4c06"
|
||||||
},
|
},
|
||||||
"OSBETAWin3.4.51": {
|
"OSBETAiOS3.6.53": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12267173_87c48b19cccf_e57c755c3b27d6",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12291938_90c393f370b8_ecf686154f9ea4",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12295568_47061d21355e_62b79a4851861d",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12279762_593428c5dc22_788410d8dabf6a"
|
||||||
},
|
},
|
||||||
"OSBETAiOS3.3.51": {
|
"OSBETAiOS3.6.54": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10451237_a3aa836fce75_f560b891c0d21e",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10459782_ced8509d61c9_cdbde1049f2207",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12352492_feecc2905bb5_9818fd3412fb03",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10434495_6bff50432edd_1641e3e19f1244",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12376047_ae7b1dea185c_bfd4bb5bbba6e2",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10429797_be4a832b1c47_f58faff155c2c4"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12354437_5c734713021d_d960d7478c00e1",
|
||||||
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_12379030_f3f1c49d9ea2_f084aab210cdfc"
|
||||||
},
|
},
|
||||||
"OSBETAiOS3.3.52": {
|
"OSBETAiOS3.7.51": {
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10478982_243ce40577bf_000895ae562404",
|
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10494861_2ed49bac2846_b7f8d02fced269",
|
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_12579793_48327ff319b5_1b794dd1071e3a",
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10479565_234d9d8dfe49_b0890465b5ae4f",
|
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_12611332_5f583f2f54ae_c04979f13c950d",
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10489293_ba258955cec6_d8347bc2994eab"
|
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_12579929_9566349ee5fb_c6341faaf9b027",
|
||||||
},
|
|
||||||
"OSBETAiOS3.3.53": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10553897_658616122c5e_1311a7ab7701f7",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10564145_db8507c78423_dc92dd047d442d",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10554126_56a3036b1f8c_6dab2038cb17c3",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
|
||||||
},
|
|
||||||
"OSBETAiOS3.3.54": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10614355_acdef3b37542_7c05a0c7169b39",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10643219_d0afbb4454ef_5ee89a3a8453cf",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10614562_0a9931c21f8d_d14b4994f719ef",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10620104_9313ee61e16d_574ea402695fa2"
|
|
||||||
},
|
|
||||||
"OSBETAiOS3.3.55": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10680207_39a321e6cd21_5498e87fbd0271",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10680207_86c7a513739e_b3e04f1f843fc8",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10680696_4c8a486b535c_bec778e9be0475",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10699045_b68581c5e40a_b431fce3552eec"
|
|
||||||
},
|
|
||||||
"OSBETAiOS3.4.51": {
|
|
||||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_10897443_f25d08d935bf_770a3e243970a0",
|
|
||||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_10898900_1b2e58b9a26e_0861bee3e89d40",
|
|
||||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_10872485_88661d25b99c_8af3232d484baf",
|
|
||||||
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_10894308_758b6d45fde6_ac9089c9b1e0a0"
|
|
||||||
},
|
|
||||||
"OSPRODAndroid3.2.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia",
|
|
||||||
"lua_url": "client version not match"
|
|
||||||
},
|
|
||||||
"OSPRODAndroid3.3.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia"
|
|
||||||
},
|
|
||||||
"OSPRODWin3.2.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia",
|
|
||||||
"lua_url": "client version not match"
|
|
||||||
},
|
|
||||||
"OSPRODWin3.3.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia"
|
|
||||||
},
|
|
||||||
"OSPRODiOS3.2.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia",
|
|
||||||
"lua_url": "client version not match"
|
|
||||||
},
|
|
||||||
"OSPRODiOS3.3.0": {
|
|
||||||
"asset_bundle_url": "prod_official_asia"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">FireflyGo-3.4.5X</string>
|
<string name="app_name">Firefly Go</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.FireflyPsAndorid" parent="android:Theme.Material.Light.NoActionBar" />
|
<style name="Theme.FireflyGoAndroid" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
</resources>
|
</resources>
|
||||||
3
app/src/main/res/xml/file_paths.xml
Normal file
3
app/src/main/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<external-files-path name="downloads" path="Download/"/>
|
||||||
|
</paths>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.fireflypsandorid
|
package com.example.firefly_go_android
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
# Android operating system, and which are packaged with your app's APK
|
# Android operating system, and which are packaged with your app's APK
|
||||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
org.gradle.parallel=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
# Kotlin code style for this project: "official" or "obsolete":
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
@@ -21,3 +22,5 @@ kotlin.code.style=official
|
|||||||
# resources declared in the library itself and none from the library's dependencies,
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
# thereby reducing the size of the R class for that library
|
# thereby reducing the size of the R class for that library
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
|
#org.gradle.configuration-cache=false
|
||||||
|
android.r8.optimizedResourceShrinking=true
|
||||||
|
|||||||
@@ -1,29 +1,48 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.9.1"
|
activityComposeVersion = "1.11.0"
|
||||||
kotlin = "2.0.21"
|
agp = "8.13.0"
|
||||||
coreKtx = "1.10.1"
|
androidxJunit = "1.3.0"
|
||||||
|
animationCore = "1.9.3"
|
||||||
|
autoupdater = "1.0.1"
|
||||||
|
espressoCoreVersion = "3.7.0"
|
||||||
|
foundation = "1.9.3"
|
||||||
|
kotlin = "2.2.20"
|
||||||
|
coreKtx = "1.17.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.1.5"
|
lifecycleRuntimeKtxVersion = "2.9.4"
|
||||||
espressoCore = "3.5.1"
|
material = "1.9.3"
|
||||||
lifecycleRuntimeKtx = "2.6.1"
|
material3WindowSizeClass = "1.4.0"
|
||||||
activityCompose = "1.8.0"
|
materialIconsExtended = "1.7.8"
|
||||||
composeBom = "2024.09.00"
|
slf4jAndroidVersion = "1.7.36"
|
||||||
|
ui = "1.9.3"
|
||||||
|
uiGraphics = "1.9.3"
|
||||||
|
uiTestJunit4 = "1.9.3"
|
||||||
|
uiTestManifest = "1.9.3"
|
||||||
|
uiTooling = "1.9.3"
|
||||||
|
uiToolingPreview = "1.9.3"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
androidx-activity-compose-v1101 = { module = "androidx.activity:activity-compose", version.ref = "activityComposeVersion" }
|
||||||
|
androidx-animation = { module = "androidx.compose.animation:animation", version.ref = "animationCore" }
|
||||||
|
androidx-animation-core = { module = "androidx.compose.animation:animation-core", version.ref = "animationCore" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
androidx-espresso-core-v370 = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCoreVersion" }
|
||||||
|
androidx-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "foundation" }
|
||||||
|
androidx-junit-v130 = { module = "androidx.test.ext:junit", version.ref = "androidxJunit" }
|
||||||
|
androidx-lifecycle-runtime-ktx-v293 = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtxVersion" }
|
||||||
|
androidx-material = { module = "androidx.compose.material:material", version.ref = "material" }
|
||||||
|
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
|
||||||
|
androidx-material3-window-size-class1 = { module = "androidx.compose.material3:material3-window-size-class", version.ref = "material3WindowSizeClass" }
|
||||||
|
autoupdater = { module = "com.github.CSAbhiOnline:AutoUpdater", version.ref = "autoupdater" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
material3 = { module = "androidx.compose.material3:material3", version.ref = "material3WindowSizeClass" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
slf4j-android = { module = "org.slf4j:slf4j-android", version.ref = "slf4jAndroidVersion" }
|
||||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
ui = { module = "androidx.compose.ui:ui", version.ref = "ui" }
|
||||||
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
ui-graphics = { module = "androidx.compose.ui:ui-graphics", version.ref = "uiGraphics" }
|
||||||
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "uiTestJunit4" }
|
||||||
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
|
ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "uiTestManifest" }
|
||||||
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "uiTooling" }
|
||||||
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "uiToolingPreview" }
|
||||||
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
|
||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Mon Apr 28 17:05:34 ICT 2025
|
#Wed Oct 08 15:20:16 ICT 2025
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:59349c9ff1ff339ba944ae3a17e264a05a1aef5de54912b227aeee3439f493d0
|
|
||||||
size 72126254
|
|
||||||
3
script/README_Note.md
Normal file
3
script/README_Note.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## - UPDATE: 3.7.52
|
||||||
BIN
script/release-uploader
Normal file
BIN
script/release-uploader
Normal file
Binary file not shown.
5
script/release.json
Normal file
5
script/release.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"tag": "3.7.2-01",
|
||||||
|
"title": "PreBuild Version 3.7.52 - 01"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
|
maven {
|
||||||
|
setUrl("https://jitpack.io")
|
||||||
|
}
|
||||||
google {
|
google {
|
||||||
content {
|
content {
|
||||||
includeGroupByRegex("com\\.android.*")
|
includeGroupByRegex("com\\.android.*")
|
||||||
@@ -9,15 +12,20 @@ pluginManagement {
|
|||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
repositories {
|
repositories {
|
||||||
|
maven {
|
||||||
|
setUrl("https://jitpack.io")
|
||||||
|
}
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = "FireflyPsAndorid"
|
rootProject.name = "FireflyGoAndroid"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|||||||
Reference in New Issue
Block a user