3 Commits

Author SHA1 Message Date
7722e5fa70 UPDATE: Re-optimize performance 2025-10-04 21:16:44 +07:00
dafb6aba1b UPDATE: New res 2025-10-03 22:03:27 +07:00
3e967d7bed UPDATE: New res 2025-10-03 22:02:57 +07:00
11 changed files with 126 additions and 30 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@
.externalNativeBuild
.cxx
local.properties
.history/

View File

@@ -18,12 +18,12 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/Theme.FireflyPsAndorid"
android:theme="@style/Theme.FireflyGoAndroid"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.FireflyPsAndorid">
android:theme="@style/Theme.FireflyGoAndroid">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@@ -4,8 +4,8 @@ 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.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
@@ -14,6 +14,7 @@ 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() {
@@ -47,20 +48,29 @@ class GolangServerService : Service() {
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("FireflyGO is running...")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.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()
wakeLock?.acquire(10*60*1000L)
Log.d(TAG, "✅ WakeLock acquired")
} catch (e: Exception) {
Log.e(TAG, "❌ WakeLock failed", e)
@@ -106,7 +116,6 @@ class GolangServerService : Service() {
Log.e(TAG, "Error shutting down server", e)
}
// 2. Giải phóng WakeLock nếu còn giữ
try {
wakeLock?.let {
if (it.isHeld) {
@@ -132,7 +141,7 @@ class GolangServerService : Service() {
description = "Channel for running Golang backend in foreground"
}
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
Log.d(TAG, "✅ Notification channel created")
}

View File

@@ -16,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.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
@@ -56,12 +55,17 @@ 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
data class AppVersion(
val latestVersion: String,
@@ -98,7 +102,7 @@ class MainActivity : ComponentActivity() {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Box(modifier = Modifier.fillMaxSize()) {
ServerControlScreen(appDataPath, dataDir, appVersion, Modifier.padding(innerPadding))
AutoUpdateDialog(onDismiss = {}, appVersion, true)
AutoUpdateDialog(onDismiss = {}, appVersion, dataDir, true)
}
}
}
@@ -126,6 +130,28 @@ fun copyRawToFile(context: Context, targetDir: File, fileName: String, resId: In
}
}
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) {
@@ -161,7 +187,7 @@ fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersi
) {
// Title
Text(
text = "Firefly Ps for Android",
text = "Firefly GO for Android",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 24.dp),
@@ -248,7 +274,6 @@ fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersi
horizontalArrangement = Arrangement.spacedBy(32.dp),
verticalAlignment = Alignment.CenterVertically
) {
val context = LocalContext.current
// Check Update widget
Column(
@@ -381,7 +406,9 @@ fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersi
// Auto Update Dialog
if (showUpdateDialog) {
AutoUpdateDialog(
onDismiss = { showUpdateDialog = false }, appVersion
onDismiss = { showUpdateDialog = false },
appVersion,
dataDir
)
}
}
@@ -394,6 +421,63 @@ fun parseGoLogLine(line: String): String? {
return if (content.isNullOrBlank()) null else content
}
fun parseAnsi(text: String): AnnotatedString {
val regex = Regex("\u001B\\[(\\d+)(;\\d+)*m")
val builder = buildAnnotatedString {
var lastIndex = 0
var currentColor = Color.Black
for (match in regex.findAll(text)) {
val start = match.range.first
val before = text.substring(lastIndex, start)
withStyle(SpanStyle(color = currentColor)) {
append(before)
}
val code = match.groupValues[1].toInt()
currentColor = when (code) {
30 -> {
Color.Black
}
31 -> {
Color.Red
}
32 -> {
Color(0xFF00C853)
}
33 -> {
Color(0xFFFFD600)
}
34 -> {
Color(0xFF2962FF)
}
35 -> {
Color(0xFFD500F9)
}
36 -> {
Color(0xFF00B8D4)
}
37 -> {
Color.White
}
else -> {
Color.Black
}
}
lastIndex = match.range.last + 1
}
val remain = text.substring(lastIndex)
withStyle(SpanStyle(color = currentColor)) {
append(remain)
}
}
return builder
}
@Composable
fun LogPopup(
@@ -444,19 +528,16 @@ fun LogPopup(
)
Spacer(modifier = Modifier.height(8.dp))
LazyColumn(
state = listState,
modifier = Modifier.weight(1f)
) {
LazyColumn(state = listState, modifier = Modifier.weight(1f)) {
items(logs.size) { index ->
Text(
text = logs[index],
text = parseAnsi(logs[index]),
fontSize = 12.sp,
color = Color.Black,
modifier = Modifier.padding(vertical = 2.dp)
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Button(
onClick = { onDismiss() },
@@ -475,6 +556,7 @@ fun LogPopup(
fun AutoUpdateDialog(
onDismiss: () -> Unit,
appVersion: AppVersion,
dataDir: File,
isFirstOpen: Boolean = false
) {
val context = LocalContext.current
@@ -522,6 +604,10 @@ fun AutoUpdateDialog(
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)
}
}
@@ -601,7 +687,7 @@ fun AutoUpdateDialog(
autoUpdaterManager.downloadapk(
context,
update!!.apk_url,
"MyApp_${update!!.latestversion}.apk"
"FireflyGO_${update!!.latestversion}.apk"
) { prog -> progress = prog }
}
}

View File

@@ -1,5 +1,5 @@
{
"latest_version": "3.6.2-03",
"changelog": "UPDATE: Extra setting",
"apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/releases/download/3.6.2-03/firefly_go_android.apk"
"latest_version": "3.6.2-05",
"changelog": "UPDATE: Re-optimize performance",
"apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/releases/download/3.6.2-05/firefly_go_android.apk"
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.FireflyPsAndorid" parent="android:Theme.Material.Light.NoActionBar" />
<style name="Theme.FireflyGoAndroid" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@@ -15,7 +15,7 @@ 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
android.enableJetifier=false
# 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

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:957b22de20769b6ed13aa638daf20609c5568c317302e62c98b05b11426b9851
size 89626137
oid sha256:b2890a23bc1bad9326247f5b8a055f7bfe93eeaaf0e89e220fe27cf9aedf07b5
size 89623442

View File

@@ -1,2 +1,2 @@
# Changelog
UPDATE: Fix env
## - UPDATE: Re-optimize performance

View File

@@ -1,5 +1,5 @@
{
"tag": "3.6.2-02",
"title": "PreBuild Version 3.6.52 - 02"
"tag": "3.6.2-05",
"title": "PreBuild Version 3.6.52 - 05"
}