7 Commits
Author SHA1 Message Date
Mathew Tkachuk 1b081964d5 chore: Bump version 2025-03-08 16:47:49 +03:00
Mathew Tkachuk 47a2f5815d refactor: UI code refactors 2025-03-08 16:47:41 +03:00
Mathew Tkachuk 0aad2646fe chore: Add monochrome icon 2025-03-08 16:41:03 +03:00
Mathew Tkachuk 3fbd6b61bd feat: Compatibility status 2025-03-08 16:33:46 +03:00
Mathew Tkachuk 479deff61a refactor: Activity launcher categories
Should fix YVR behavior.
2025-03-08 14:34:35 +03:00
Mathew Tkachuk 3c6b910233 fix: Add default values for configs 2025-03-08 13:53:42 +03:00
Mathew Tkachuk c4fc748024 fix: Fix patch Fix Unreal Engine 4 crash 2025-03-08 11:25:00 +03:00
18 changed files with 390 additions and 151 deletions

No files matched your search

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
@@ -8,4 +8,9 @@
<string name="cant_update_overport">overport libraries cannot be downloaded.</string>
<string name="unknown_error">Unknown error has been occurred.</string>
<string name="update_available">Update available!</string>
<string name="status_unknown">Unknown</string>
<string name="status_playable">Playable</string>
<string name="status_has_problems">Has problems</string>
<string name="status_not_working">Not working</string>
<string name="status_loading">Loading…</string>
</resources>
@@ -11,4 +11,4 @@ class AndroidPlatform(override val name: String) : Platform
expect fun getPlatform(): Platform
// TODO This should be controlled by Gradle.
fun getCurrentVersion(): String = "1.0.0"
fun getCurrentVersion(): String = "1.1.0"
@@ -7,25 +7,25 @@ import kotlinx.serialization.json.Json
@Serializable
data class FrdaAsset(
@SerialName("ID")
val id: Long,
val path: String,
val id: Long = 0,
val path: String = "",
val type: String = "store"
)
@Serializable
data class FrdaParameters(
val assets: List<FrdaAsset>,
val skus: List<String>
val assets: List<FrdaAsset> = listOf(),
val skus: List<String> = listOf()
)
@Serializable
data class FrdaInteraction(
val parameters: FrdaParameters
val parameters: FrdaParameters = FrdaParameters(),
)
@Serializable
data class FrdaConfig(
val interaction: FrdaInteraction
val interaction: FrdaInteraction = FrdaInteraction(),
)
private val json = Json { ignoreUnknownKeys = true }
@@ -0,0 +1,32 @@
package moe.crx.ovrport.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GithubIssueLabel(
@SerialName("id")
val id: Long,
@SerialName("name")
val name: String,
@SerialName("color")
val color: String,
)
@Serializable
data class GithubIssue(
@SerialName("html_url")
var htmlUrl: String,
@SerialName("title")
val title: String,
@SerialName("created_at")
val createdAt: String,
@SerialName("labels")
val labels: List<GithubIssueLabel>
)
@Serializable
data class GithubIssues(
@SerialName("items")
val items: List<GithubIssue>
)
@@ -1,9 +1,130 @@
package moe.crx.ovrport.patch
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import kotlinx.serialization.json.Json
import moe.crx.ovrport.model.GithubIssues
import moe.crx.ovrport.patch.Constants.UNKNOWN_COMPATIBILITY
import moe.crx.ovrport.utils.HttpUtil.download
import org.jetbrains.compose.resources.StringResource
import overportapp.composeapp.generated.resources.*
import overportapp.composeapp.generated.resources.Res
import overportapp.composeapp.generated.resources.status_has_problems
import overportapp.composeapp.generated.resources.status_not_working
import overportapp.composeapp.generated.resources.status_unknown
import java.net.URLEncoder
private val json = Json { ignoreUnknownKeys = true }
object Constants {
const val APK_MIMETYPE = "application/vnd.android.package-archive"
const val OVRPORT_VERSION = "3.2.2"
const val LIBRARIES_URL = "https://files.crx.moe/ovrport/tracker/releases/download/$OVRPORT_VERSION/libraries.zip"
const val LIBRARIES_DIR = "libraries/$OVRPORT_VERSION"
const val RELEASES_URL = "https://api.github.com/repos/ovrport/app/releases"
const val ISSUES_URL = "https://api.github.com/search/issues?q=%s+repo:ovrport/tracker"
private const val TRACKER_URL = "https://github.com/ovrport/tracker/issues"
val UNKNOWN_COMPATIBILITY = CompatibilityStatusInfo(CompatibilityStatus.UNKNOWN, TRACKER_URL)
val LOADING_COMPATIBILITY = CompatibilityStatusInfo(CompatibilityStatus.LOADING, TRACKER_URL)
}
enum class CompatibilityStatus(
val labelName: String,
val icon: ImageVector,
val nameResource: StringResource,
val cardColor: Color,
val contentColor: Color,
) {
LOADING(
"Loading",
Icons.Default.Sync,
Res.string.status_loading,
Color(0xFF483f77),
Color(0xFFe6deff),
),
UNKNOWN(
"Unknown",
Icons.Default.QuestionMark,
Res.string.status_unknown,
Color(0xFF354479),
Color(0xFFDCE1FF),
),
NOT_WORKING(
"Not working",
Icons.Default.Close,
Res.string.status_not_working,
Color(0xFF73332f),
Color(0xFFffdad7),
),
HAS_PROBLEMS(
"Has problems",
Icons.Default.Warning,
Res.string.status_has_problems,
Color(0xFF5b4300),
Color(0xFFffdf9f),
),
PLAYABLE(
"Playable",
Icons.Default.Check,
Res.string.status_playable,
Color(0xFF2d4f1d),
Color(0xFFc4efac),
),
}
data class CompatibilityStatusInfo(
val status: CompatibilityStatus,
val url: String,
)
fun getCompatibilityStatus(
applicationName: String?,
applicationPackage: String?
): CompatibilityStatusInfo {
val pkg = applicationName ?: ""
val name = applicationPackage ?: ""
runCatching {
val issue = json
.decodeFromString<GithubIssues>(
String(
download(
Constants.ISSUES_URL.format(
URLEncoder.encode(
pkg,
Charsets.UTF_8
)
)
)
)
)
.items.firstOrNull { it.title.contains(pkg) || it.title.contains(name) }
?: json
.decodeFromString<GithubIssues>(
String(
download(
Constants.ISSUES_URL.format(
URLEncoder.encode(
name,
Charsets.UTF_8
)
)
)
)
)
.items.firstOrNull { it.title.contains(pkg) || it.title.contains(name) }
issue?.labels?.forEach { label ->
CompatibilityStatus.entries.forEach { status ->
if (status.labelName == label.name) {
return CompatibilityStatusInfo(status, issue.htmlUrl)
}
}
}
}
return UNKNOWN_COMPATIBILITY
}
@@ -14,8 +14,8 @@ class FileTransformer(val file: File) {
file.writeText(Regex(input, RegexOption.DOT_MATCHES_ALL).replace(file.readText(), output))
}
fun find(input: String): Boolean {
return Regex(input, RegexOption.DOT_MATCHES_ALL).find(file.readText()) != null
fun readText(): String {
return file.readText()
}
fun append(line: String) {
@@ -158,7 +158,10 @@ class PatchExecutor(private val workingDir: File) {
it ?: workingDir.resolve("smali/classes").apply { mkdirs() }
}
.resolve("${fileName}.smali")
.apply { createNewFile() }
.apply {
parentFile?.mkdirs()
createNewFile()
}
.run {
if (exists()) {
FileTransformer(this).block()
@@ -184,15 +184,22 @@ object PatchStore {
takeNodesEach({ named("application") }) {
takeNodesEach({ named("activity") }) {
takeNodesEach({ named("intent-filter") }) {
takeNodesEach({ named("category") }) {
when (attributeName()) {
"android.intent.category.INFO" -> null
"android.intent.category.LAUNCHER" -> null
else -> this
val hasIntent = elem<JSONArray>("nodes").elemEach<JSONObject> { named("category") }.map {
when (it.attributeName()) {
"com.oculus.intent.category.VR" -> true
"android.intent.category.LAUNCHER" -> true
else -> false
}
}
}.reduceOrNull { l, r -> l || r } ?: false
takeNodes {
this?.put(createCategory("android.intent.category.LAUNCHER"))
if (!hasIntent) this else {
JSONArray()
.put(createAction("android.intent.action.MAIN"))
.put(createCategory("android.intent.category.LAUNCHER"))
.put(createCategory("com.oculus.intent.category.VR"))
.put(createCategory("com.yvr.intent.category.VR"))
}
}
}
}
@@ -216,7 +223,7 @@ object PatchStore {
}
PATCHES += Patch("Fix Unreal Engine 4 crash") {
createSmali("com/unity3d/player/UnityPlayer") {
if (!find(".*")) {
if (readText().isBlank()) {
append(".class public Lcom/unity3d/player/UnityPlayer;")
append(".super Ljava/lang/Object;")
append(".field public static currentActivity:Landroid/app/Activity;")
@@ -1,8 +1,5 @@
package moe.crx.ovrport.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
@@ -11,7 +8,6 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CloudDownload
import androidx.compose.material.icons.filled.Download
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -22,16 +18,14 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import moe.crx.ovrport.AndroidPlatform
import moe.crx.ovrport.getCurrentVersion
import moe.crx.ovrport.patch.Patch
import moe.crx.ovrport.getPlatform
import moe.crx.ovrport.model.GithubRelease
import moe.crx.ovrport.patch.Constants
import moe.crx.ovrport.patch.Patch
import moe.crx.ovrport.ui.theme.OverportTheme
import moe.crx.ovrport.utils.HttpUtil
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import overportapp.composeapp.generated.resources.Res
@@ -79,16 +73,11 @@ fun AppContent(
Constants.OVRPORT_VERSION,
modifier = Modifier.padding(8.dp),
fontSize = 18.sp,
color = MaterialTheme.colorScheme.secondary
)
}
},
actions = {
AnimatedVisibility(
versionToUpdate?.name != null && versionToUpdate?.name != getCurrentVersion(),
enter = fadeIn(),
exit = fadeOut()
) {
FadeVisibility(versionToUpdate?.name != null && versionToUpdate?.name != getCurrentVersion()) {
Row(
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(
RoundedCornerShape(16.dp)
@@ -103,7 +92,6 @@ fun AppContent(
Text(
stringResource(Res.string.update_available),
fontSize = 18.sp,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier.padding(0.dp, 8.dp, 8.dp, 8.dp),
)
}
@@ -118,21 +106,13 @@ fun AppContent(
val inProgress = viewModel.working
val isPatcherVisible = viewModel.isApkLoaded() && !inProgress
AnimatedVisibility(
!isPatcherVisible,
enter = fadeIn(),
exit = fadeOut()
) {
FadeVisibility(!isPatcherVisible) {
StartingCard(innerPadding, inProgress) {
onOpen()
}
}
AnimatedVisibility(
isPatcherVisible,
enter = fadeIn(),
exit = fadeOut()
) {
FadeVisibility(isPatcherVisible) {
ApplicationInfoCard(
innerPadding,
viewModel.currentAppName(),
@@ -0,0 +1,52 @@
package moe.crx.ovrport.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Widgets
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.stringResource
import overportapp.composeapp.generated.resources.Res
import overportapp.composeapp.generated.resources.unknown_package
@Composable
fun ApplicationInfo(
applicationName: String? = "Application",
applicationPackage: String? = "com.company.application",
applicationVersion: String? = "1.0.0",
applicationIcon: ImageBitmap? = null,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
if (applicationIcon == null) {
Icon(
Icons.Default.Widgets,
contentDescription = null,
modifier = Modifier.size(48.dp)
)
} else {
Image(
applicationIcon,
contentDescription = null,
modifier = Modifier.size(48.dp).clip(RoundedCornerShape(8.dp))
)
}
Column(
modifier = Modifier.height(48.dp),
verticalArrangement = Arrangement.Center
) {
Text("$applicationName ($applicationVersion)")
Text(
applicationPackage ?: stringResource(Res.string.unknown_package),
)
}
}
}
@@ -1,36 +1,22 @@
package moe.crx.ovrport.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ListItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.unit.dp
import moe.crx.ovrport.patch.Patch
import moe.crx.ovrport.patch.PatchStore
import org.jetbrains.compose.ui.tooling.preview.Preview
import androidx.compose.material.icons.filled.Widgets
import androidx.compose.material3.*
import org.jetbrains.compose.resources.stringResource
import overportapp.composeapp.generated.resources.Res
import overportapp.composeapp.generated.resources.unknown_package
@OptIn(ExperimentalLayoutApi::class)
@Composable
@@ -38,7 +24,7 @@ import overportapp.composeapp.generated.resources.unknown_package
fun ApplicationInfoCard(
innerPadding: PaddingValues = PaddingValues(16.dp),
applicationName: String? = "Application",
applicationPackage: String? = "com.company.application",
applicationPackage: String? = "",
applicationVersion: String? = "1.0.0",
applicationIcon: ImageBitmap? = null,
onCancel: () -> Unit = {},
@@ -49,32 +35,11 @@ fun ApplicationInfoCard(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
FlowRow(
modifier = Modifier.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
modifier = Modifier.fillMaxWidth().padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
if (applicationIcon == null) {
Icon(
Icons.Default.Widgets,
contentDescription = null,
modifier = Modifier.size(48.dp)
)
} else {
Image(
applicationIcon,
contentDescription = null,
modifier = Modifier.size(48.dp).clip(RoundedCornerShape(8.dp))
)
}
Column(
modifier = Modifier.height(48.dp),
verticalArrangement = Arrangement.Center
) {
Text("$applicationName ($applicationVersion)")
Text(
applicationPackage ?: stringResource(Res.string.unknown_package),
color = MaterialTheme.colorScheme.secondary
)
}
ApplicationInfo(applicationName, applicationPackage, applicationVersion, applicationIcon)
ApplicationStatus(applicationName, applicationPackage)
}
val patches = remember { mutableStateListOf(*PatchStore.PATCHES.toTypedArray()) }
@@ -0,0 +1,57 @@
package moe.crx.ovrport.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import moe.crx.ovrport.patch.Constants.LOADING_COMPATIBILITY
import moe.crx.ovrport.patch.getCompatibilityStatus
import org.jetbrains.compose.resources.stringResource
@Composable
fun ApplicationStatus(
applicationName: String? = "Application",
applicationPackage: String? = "",
) {
var statusInfo by remember(applicationPackage) { mutableStateOf(LOADING_COMPATIBILITY) }
val urlHandler = LocalUriHandler.current
LaunchedEffect(applicationPackage) {
withContext(Dispatchers.IO) {
statusInfo = getCompatibilityStatus(applicationName, applicationPackage)
}
}
Card(colors = CardDefaults.cardColors(statusInfo.status.cardColor, statusInfo.status.contentColor)) {
Row(
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(
RoundedCornerShape(16.dp)
).clickable {
urlHandler.openUri(statusInfo.url)
}) {
Icon(
statusInfo.status.icon,
contentDescription = null,
modifier = Modifier.padding(16.dp),
)
Text(
stringResource(statusInfo.status.nameResource),
fontSize = 18.sp,
modifier = Modifier.padding(0.dp, 16.dp, 16.dp, 16.dp),
)
}
}
}
@@ -0,0 +1,37 @@
package moe.crx.ovrport.ui
import androidx.compose.animation.core.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Bolt
import androidx.compose.material3.Icon
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import kotlinx.coroutines.delay
@Composable
fun BreathingIcon(modifier: Modifier, duration: Int = 1500) {
var isFaded by remember { mutableStateOf(false) }
val alpha by animateFloatAsState(
targetValue = if (isFaded) 0.2f else 1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = duration, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
label = ""
)
LaunchedEffect(Unit) {
while (true) {
isFaded = !isFaded
delay(duration.toLong())
}
}
Icon(
Icons.Default.Bolt,
contentDescription = null,
modifier = modifier.alpha(alpha)
)
}
@@ -0,0 +1,20 @@
package moe.crx.ovrport.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
@Composable
fun FadeVisibility(
condition: Boolean,
block: @Composable AnimatedVisibilityScope.() -> Unit
) {
AnimatedVisibility(
condition,
enter = fadeIn(),
exit = fadeOut(),
content = block
)
}
@@ -1,37 +1,14 @@
package moe.crx.ovrport.ui
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddCircle
import androidx.compose.material.icons.filled.Bolt
import androidx.compose.material.icons.filled.Download
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.rotate
@@ -40,7 +17,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import moe.crx.ovrport.AndroidPlatform
import moe.crx.ovrport.getPlatform
import org.jetbrains.compose.resources.stringResource
@@ -126,30 +102,3 @@ fun StartingCard(
}
}
}
@Composable
fun BreathingIcon(modifier: Modifier, duration: Int = 1500) {
var isFaded by remember { mutableStateOf(false) }
val alpha by animateFloatAsState(
targetValue = if (isFaded) 0.2f else 1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = duration, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
label = ""
)
LaunchedEffect(Unit) {
while (true) {
isFaded = !isFaded
delay(duration.toLong())
}
}
Icon(
Icons.Default.Bolt,
contentDescription = null,
modifier = modifier.alpha(alpha)
)
}
@@ -5,6 +5,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
@@ -16,16 +17,6 @@ private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40,
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
@@ -86,3 +86,22 @@ fun createCategory(value: String): JSONObject {
)
)
}
fun createAction(value: String): JSONObject {
return JSONObject()
.put("node_type", "element")
.put("name", "action")
.put(
"attributes",
JSONArray()
.put(
JSONObject()
.put("name", "name")
.put("id", 16842755)
.put("uri", "http://schemas.android.com/apk/res/android")
.put("prefix", "android")
.put("value_type", "STRING")
.put("data", value)
)
)
}
+1 -1
View File
@@ -10,4 +10,4 @@ android.nonTransitiveRClass=true
android.useAndroidX=true
#Application
appVersion=1.0.0
appVersion=1.1.0