mirror of
https://github.com/ovrport/app.git
synced 2026-10-26 19:19:56 -04:00
feat: Compatibility status
This commit is contained in:
1 parent
479deff61a
commit
3fbd6b61bd
7 files changed
+247
-56
No files matched your search
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
@@ -11,7 +11,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
|
||||
@@ -79,7 +78,6 @@ fun AppContent(
|
||||
Constants.OVRPORT_VERSION,
|
||||
modifier = Modifier.padding(8.dp),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -103,7 +101,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),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,43 +2,110 @@ 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.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.material.icons.filled.Widgets
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
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.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 moe.crx.ovrport.patch.getCompatibilityStatus
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
@Preview
|
||||
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 +116,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()) }
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user