8 Commits

Author SHA1 Message Date
e61bb39fc5 UPDATE: Update for v4 2025-09-02 14:18:06 +07:00
8f86f3ea61 UPDATE: Add self update, reset data, logs 2025-08-25 09:56:01 +07:00
d57f7c024b UPDATE: Add self update, reset data, logs 2025-08-25 09:54:12 +07:00
aec3601f2a UPDATE: Add self update, reset data, logs 2025-08-25 09:52:03 +07:00
b54d8bd0c5 FIX: add asset bundle url b 2025-08-19 16:32:14 +07:00
89a772152b FIX: add new resdata 2025-08-19 12:23:08 +07:00
ed411fc284 UPDATE: update for 3.5.1 2025-08-19 11:18:08 +07:00
b7b0457685 FIX: app runing state bug 2025-08-06 19:09:41 +07:00
18 changed files with 7082 additions and 6890 deletions

Binary file not shown.

View File

@@ -27,34 +27,61 @@ android {
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.0"
}
}
dependencies {
implementation("androidx.core:core-ktx:1.13.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.9.3")
implementation("androidx.activity:activity-compose:1.10.1")
// Compose UI
implementation("androidx.compose.ui:ui:1.9.0")
implementation("androidx.compose.ui:ui-graphics:1.9.0")
implementation("androidx.compose.ui:ui-tooling-preview:1.9.0")
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
// Foundation & Animation
implementation("androidx.compose.foundation:foundation:1.9.0")
implementation("androidx.compose.animation:animation:1.9.0")
implementation("androidx.compose.animation:animation-core:1.9.0")
// Material & Material3
implementation("androidx.compose.material:material:1.9.0")
implementation("androidx.compose.material:material-icons-extended:1.7.8")
implementation("androidx.compose.material3:material3:1.3.2")
implementation("androidx.compose.material3:material3-window-size-class:1.3.2")
// Auto updater library
implementation("com.github.CSAbhiOnline:AutoUpdater:1.0.1")
// Unit Test
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
// Android Instrumentation Test
androidTestImplementation("androidx.test.ext:junit:1.3.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.9.0")
// Debug
debugImplementation("androidx.compose.ui:ui-tooling:1.9.0")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.9.0")
// Local AAR library
implementation(files("../library/firefly-go.aar"))
}

View File

@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.READ_LOGS"/>
<application
android:allowBackup="true"
@@ -32,6 +34,17 @@
android:name=".GolangServerService"
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>
</manifest>

View File

@@ -10,6 +10,9 @@ 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 libandroid.Libandroid
@@ -19,6 +22,7 @@ class GolangServerService : Service() {
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
@@ -29,9 +33,13 @@ class GolangServerService : Service() {
}
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")
// 1. Tạo intent để mở lại MainActivity khi người dùng click vào thông báo
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
@@ -40,18 +48,15 @@ class GolangServerService : Service() {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 2. Tạo notification
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Golang Server")
.setContentText("Server đang chạy")
.setContentTitle("FireflyGO Server")
.setContentText("FireflyGO is running...")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.build()
// 3. Chạy foreground
startForeground(NOTIFICATION_ID, notification)
// 4. Giữ CPU không sleep (tùy chọn, nhưng hữu ích)
try {
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GolangServer::WakeLock")
@@ -61,7 +66,6 @@ class GolangServerService : Service() {
Log.e(TAG, "❌ WakeLock failed", e)
}
// 5. Chạy server trong thread riêng
Thread {
try {
val appDataPath = intent?.getStringExtra("appDataPath")
@@ -69,16 +73,23 @@ class GolangServerService : Service() {
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
}
@@ -89,6 +100,7 @@ class GolangServerService : Service() {
// 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)
@@ -105,6 +117,7 @@ class GolangServerService : Service() {
} catch (e: Exception) {
Log.e(TAG, "❌ Failed to release WakeLock", e)
}
isRunning = false
}
override fun onBind(intent: Intent?): IBinder? = null

View File

@@ -1,8 +1,11 @@
package com.example.fireflypsandorid
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
@@ -13,7 +16,6 @@ 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.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
@@ -21,12 +23,54 @@ 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.fireflypsandorid.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.items
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.TextStyle
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
data class AppVersion(
val latestVersion: String,
val changelog: String,
val apkUrl: String
)
class MainActivity : ComponentActivity() {
private val tag = "AppInit"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -34,53 +78,83 @@ class MainActivity : ComponentActivity() {
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)
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 ->
ServerControlScreen(appDataPath, Modifier.padding(innerPadding))
Box(modifier = Modifier.fillMaxSize()) {
ServerControlScreen(appDataPath, dataDir, appVersion, Modifier.padding(innerPadding))
AutoUpdateDialog(onDismiss = {}, appVersion, true)
}
}
}
}
private fun checkAndCreateFile(targetDir: File, fileName: String, resId: Int) {
}
}
fun copyRawToFile(context: Context, targetDir: File, fileName: String, resId: Int, override: Boolean = false) {
val outFile = File(targetDir, fileName)
if (!outFile.exists()) {
if (!outFile.exists() || override) {
try {
resources.openRawResource(resId).use { input ->
context.resources.openRawResource(resId).use { input ->
FileOutputStream(outFile).use { output ->
input.copyTo(output)
}
}
Log.i(tag, "✅ Copied $fileName to ${outFile.absolutePath}")
Log.i("FileCopy", "${if (override) "✅ Overridden" else "✅ Copied"} $fileName to ${outFile.absolutePath}")
} catch (e: Exception) {
Log.e(tag, "❌ Failed to copy $fileName: ${e.message}")
Log.e("FileCopy", "❌ Failed to copy $fileName: ${e.message}")
}
} else {
Log.i(tag, " $fileName already exists at ${outFile.absolutePath}")
Log.i("FileCopy", " $fileName already exists at ${outFile.absolutePath}")
}
}
}
@SuppressLint("ImplicitSamInstance")
@Composable
fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersion, modifier: Modifier = Modifier) {
val context = LocalContext.current
var isServerRunning by remember { mutableStateOf(false) }
val isRunning = GolangServerService.isRunning
val serverImage = if (isServerRunning)
painterResource(id = R.drawable.server_running)
else
painterResource(id = R.drawable.server_stopped)
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
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.SpaceBetween,
@@ -91,32 +165,52 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
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
modifier = Modifier.padding(top = 24.dp),
color = Color.White,
style = TextStyle(
shadow = Shadow(
color = Color.Black,
offset = Offset(2f, 2f),
blurRadius = 4f
)
)
)
Spacer(modifier = Modifier.height(8.dp))
// Server status image
Image(
painter = serverImage,
// 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,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxWidth()
.height(250.dp)
.padding(8.dp)
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(8.dp))
Spacer(modifier = Modifier.height(200.dp))
// Toggle button
Button(
onClick = {
try {
isServerRunning = !isServerRunning
if (isServerRunning) {
if (!isRunning) {
val intent = Intent(context, GolangServerService::class.java)
intent.putExtra("appDataPath", appDataPath)
context.startService(intent)
@@ -128,29 +222,592 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
}
},
colors = ButtonDefaults.buttonColors(
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
containerColor = if (isRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
contentColor = Color.White
),
shape = RoundedCornerShape(12.dp),
modifier = Modifier
.fillMaxWidth(0.7f)
.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 (isServerRunning) "Stop Server" else "Start Server",
text = if (isRunning) "Stop Server" else "Start Server",
fontSize = 20.sp
)
}
Spacer(modifier = Modifier.height(4.dp))
// Server status text
// Widget icons row
Row(
horizontalArrangement = Arrangement.spacedBy(32.dp),
verticalAlignment = Alignment.CenterVertically
) {
val context = LocalContext.current
// 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 = if (isServerRunning) "Server is running" else "Server is stopped",
fontSize = 24.sp,
color = if (isServerRunning) Color(0xFF4CAF50) else Color.Gray
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
)
}
}
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
}
@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)
}
}
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 = logs[index],
fontSize = 12.sp,
color = Color.Black,
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,
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
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,
"MyApp_${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)
)
}
}
}
}
}
}

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

View File

@@ -0,0 +1,5 @@
{
"latest_version": "3.5.4-01",
"changelog": "UPDATE: Update for v4",
"apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Andoid/releases/download/3.5.4-01/firefly_go_android.apk"
}

View File

@@ -1,8 +1,8 @@
{
"leader": 1,
"leader": 0,
"lineups": {
"0": 1310,
"1": 1410,
"0": 1413,
"1": 1403,
"2": 1409,
"3": 1407
},
@@ -27,17 +27,73 @@
"1205": 1,
"1212": 1
},
"battle": {
"battle_id": 0,
"challenge": {
"challenge_id": 0,
"skip_half": 0,
"blessings": [],
"freesr": false,
"current_half": 0,
"is_in_challenge": false,
"current_stage_id": 30117121,
"path_resonance_id": 0,
"maze_buff": 0,
"first_lineup": [],
"second_lineup": []
},
"challenge_peak": {
"current_mode": "Knight",
"group_id": 1,
"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
}
]
}
}
}
},
"theory_craft": {
"hp": {
"1": 600000,
@@ -49,10 +105,10 @@
},
"profile_data": {
"cur_chat_bubble_id": 220008,
"cur_phone_theme_id": 221011,
"cur_phone_theme_id": 221012,
"cur_phone_case_id": 254001,
"cur_pam_skin_id": 252000,
"cur_pet_id": 1002,
"cur_pet_id": 1003,
"cur_avatar_player_icon": 202034,
"cur_player_personal_card": 253001,
"cur_signature": "Firefly GO By Kain",
@@ -60,8 +116,8 @@
1310,
1309,
1407,
1412,
1001
1413,
1412
],
"cur_is_display_avatar": true
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,135 @@
{
"CNBETAAndroid3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAAndroid3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"CNBETAWin3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAAndroid3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"CNBETAiOS3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAAndroid3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAAndroid3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAWin3.5.51": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11497493_b4a5d8f717df_d632f2f00b0108",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11443120_75e75bb630b2_bb1653f50a24b3",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11503893_72129078bcdf_31a0117dd0c5aa",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11475376_d8a6597dc30c_b9f6afe07715f3",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_11454524_a18a9e47d5b8_3647b1d6ce2d9a"
},
"CNBETAWin3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAWin3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAWin3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAiOS3.4.55": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11217430_23c5cfd2cafc_071126dd600bae",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11218061_68ee992558e3_fe33df3598d887",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11218130_15360461a27a_91a0fd1d2b4db3",
"CNBETAWin3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"CNBETAiOS3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"CNBETAiOS3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"CNBETAiOS3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAAndroid3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAAndroid3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAAndroid3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAWin3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAWin3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAWin3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAiOS3.5.52": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11537608_83921e2bbfb5_f15a1cc2aaba76",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11531357_ac5c50fe7c5c_5b8f1dfdef8d06",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11555075_e532a47d9e06_61b3c1ed162173",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11531873_abaa8247cede_b13c1ccb975acd",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAiOS3.5.53": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11619846_a5b546c20acf_c6ba7f65cf9eab",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11652344_6dae28086399_aaf63e0fedc33b",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11620131_ba9be3a133df_248c41962f7625",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
},
"OSBETAiOS3.5.54": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"asset_bundle_url_b": "https://autopatchcn.bhsr.com/asb/BetaLive/output_11715498_4850ed5bf0fe_76bdeb19894e7e",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_11748833_44e6507dc182_fc55ad3d7434ba",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_11715817_6b9296fec056_20fd6286275e46",
"ifix_url": "https://autopatchcn.bhsr.com/ifix/BetaLive/output_0_40d2ce0253_c61ba99f70b885"
}
}

View File

@@ -1,3 +1,3 @@
<resources>
<string name="app_name">FireflyGo-3.4.5X</string>
<string name="app_name">FireflyGo-3.5.5X</string>
</resources>

View File

@@ -0,0 +1,3 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="downloads" path="Download/"/>
</paths>

View File

@@ -15,9 +15,11 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
org.gradle.configuration-cache=true

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ab23bd9a708e04ce0817aa7e3d05e81e3bd64e8846d0df54af9647b550d30859
size 72329407
oid sha256:fbc29acc100bafe70ed46d921495ce98d93735d4c62d7af2fd78bc0f4d67651b
size 86920442

View File

@@ -16,6 +16,9 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven{
url=uri("https://jitpack.io")
}
}
}