manager: add module background banners"

module devs can add banners for their modules through module.prop config

Example:

banner=https://something.com/banner.png
This commit is contained in:
rifsxd
2025-06-03 00:29:02 +06:00
parent 3f7e731df6
commit f91afe6c46
4 changed files with 538 additions and 468 deletions

View File

@@ -96,7 +96,7 @@ fun CustomizationScreen(navigator: DestinationsNavigator) {
)
}
SwitchItem(
icon = Icons.Filled.ColorLens,
icon = Icons.Filled.Dashboard,
title = stringResource(id = R.string.settings_legacyui),
summary = stringResource(id = R.string.settings_legacyui_summary),
checked = useLagacyUI
@@ -105,6 +105,22 @@ fun CustomizationScreen(navigator: DestinationsNavigator) {
useLagacyUI = it
}
var useBanner by rememberSaveable {
mutableStateOf(
prefs.getBoolean("use_banner", true)
)
}
SwitchItem(
enabled = !useLagacyUI,
icon = Icons.Filled.ViewCarousel,
title = stringResource(id = R.string.settings_banner),
summary = stringResource(id = R.string.settings_banner_summary),
checked = useBanner
) {
prefs.edit().putBoolean("use_banner", it).apply()
useBanner = it
}
var enableAmoled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_amoled", false)

View File

@@ -1,5 +1,6 @@
package com.rifsxd.ksunext.ui.screen
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
@@ -8,6 +9,8 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -21,6 +24,7 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
@@ -68,6 +72,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -93,6 +100,7 @@ import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import coil.compose.AsyncImage
import com.rifsxd.ksunext.Natives
import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ksuApp
@@ -677,22 +685,61 @@ fun ModuleItem(
ElevatedCard(
modifier = Modifier.fillMaxWidth()
) {
Box(
modifier = Modifier
.fillMaxWidth()
) {
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val useLagacyUI = prefs.getBoolean("use_legacyui", false)
val useBanner = prefs.getBoolean("use_banner", true)
if (useBanner && !useLagacyUI && module.banner.isNotEmpty()) {
Box(
modifier = Modifier
.matchParentSize(),
contentAlignment = Alignment.Center
) {
AsyncImage(
model = module.banner,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
contentScale = ContentScale.Crop,
alpha = 0.18f
)
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(
Brush.verticalGradient(
colors = listOf(
Color.Black.copy(alpha = 0.0f),
Color.Black.copy(alpha = 0.9f)
),
startY = 0f,
endY = Float.POSITIVE_INFINITY
)
)
)
}
}
Column {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
val interactionSource = remember { MutableInteractionSource() }
val indication = LocalIndication.current
val viewModel = viewModel<ModuleViewModel>()
val context = LocalContext.current
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var developerOptionsEnabled by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_developer_options", false)
)
}
val useLagacyUI = prefs.getBoolean("use_legacyui", false)
LaunchedEffect(Unit) {
developerOptionsEnabled = prefs.getBoolean("enable_developer_options", false)
}
@@ -1181,6 +1228,8 @@ fun ModuleItem(
}
}
}
}
}
}
fun formatSize(size: Long): String {
@@ -1212,7 +1261,8 @@ fun ModuleItemPreview() {
hasWebUi = false,
hasActionScript = false,
dirId = "dirId",
size = 12345678L
size = 12345678L,
banner = ""
)
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {})
}

View File

@@ -46,7 +46,8 @@ class ModuleViewModel : ViewModel() {
val hasWebUi: Boolean,
val hasActionScript: Boolean,
val dirId: String,
val size: Long
val size: Long,
val banner: String
)
data class ModuleUpdateInfo(
@@ -142,7 +143,8 @@ class ModuleViewModel : ViewModel() {
obj.optBoolean("web"),
obj.optBoolean("action"),
dirId,
size
size,
obj.optString("banner")
)
}.toList()
isNeedRefresh = false

View File

@@ -213,6 +213,8 @@
<string name="settings_language">Language</string>
<string name="settings_legacyui">Use Legacy UI</string>
<string name="settings_legacyui_summary">Switch to the previous user interface style.</string>
<string name="settings_banner">Enable banners</string>
<string name="settings_banner_summary">Show background banners for modules.</string>
<string name="use_webuix">Use WebUI X</string>
<string name="use_webuix_summary">Use WebUI X instead of WebUI, which supports more APIs.</string>
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string>