diff --git a/.idea/GradleUpdaterPlugin.xml b/.idea/GradleUpdaterPlugin.xml
new file mode 100644
index 0000000..e359d57
--- /dev/null
+++ b/.idea/GradleUpdaterPlugin.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
index 30bab2a..d8e9561 100644
--- a/.idea/discord.xml
+++ b/.idea/discord.xml
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 46b502a..b12ff52 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -3,6 +3,7 @@ import java.io.ByteArrayOutputStream
plugins {
id("com.android.application")
kotlin("android")
+ kotlin("plugin.serialization") version "1.7.20"
}
android {
@@ -13,8 +14,8 @@ android {
applicationId = "dev.beefers.vendetta.manager"
minSdk = 24
targetSdk = 33
- versionCode = 1000
- versionName = "1.0.0"
+ versionCode = 1010
+ versionName = "1.0.1"
buildConfigField("String", "GIT_BRANCH", "\"${getCurrentBranch()}\"")
buildConfigField("String", "GIT_COMMIT", "\"${getLatestCommit()}\"")
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index ba9b13f..91b4614 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -11,7 +11,7 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
- "versionCode": 1,
+ "versionCode": 1000,
"versionName": "1.0.0",
"outputFile": "app-release.apk"
}
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/di/HttpModule.kt b/app/src/main/java/dev/beefers/vendetta/manager/di/HttpModule.kt
index 20d40dd..8e8760e 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/di/HttpModule.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/di/HttpModule.kt
@@ -1,7 +1,7 @@
package dev.beefers.vendetta.manager.di
-import dev.beefers.vendetta.manager.network.service.GithubService
import dev.beefers.vendetta.manager.network.service.HttpService
+import dev.beefers.vendetta.manager.network.service.RestService
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
@@ -14,7 +14,7 @@ val httpModule = module {
fun provideJson() = Json {
ignoreUnknownKeys = true
- coerceInputValues = true
+ isLenient = true
}
fun provideHttpClient(json: Json) = HttpClient(CIO) {
@@ -26,6 +26,6 @@ val httpModule = module {
singleOf(::provideJson)
singleOf(::provideHttpClient)
singleOf(::HttpService)
- singleOf(::GithubService)
+ singleOf(::RestService)
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/di/ManagerModule.kt b/app/src/main/java/dev/beefers/vendetta/manager/di/ManagerModule.kt
index 299188a..4590030 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/di/ManagerModule.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/di/ManagerModule.kt
@@ -1,6 +1,7 @@
package dev.beefers.vendetta.manager.di
import dev.beefers.vendetta.manager.domain.manager.DownloadManager
+import dev.beefers.vendetta.manager.domain.manager.InstallManager
import dev.beefers.vendetta.manager.domain.manager.PreferenceManager
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
@@ -8,4 +9,5 @@ import org.koin.dsl.module
val managerModule = module {
singleOf(::DownloadManager)
singleOf(::PreferenceManager)
+ singleOf(::InstallManager)
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/di/RepositoryModule.kt b/app/src/main/java/dev/beefers/vendetta/manager/di/RepositoryModule.kt
index 5295dc9..6ba01d7 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/di/RepositoryModule.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/di/RepositoryModule.kt
@@ -1,9 +1,9 @@
package dev.beefers.vendetta.manager.di
-import dev.beefers.vendetta.manager.domain.repository.GithubRepository
+import dev.beefers.vendetta.manager.domain.repository.RestRepository
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
val repositoryModule = module {
- singleOf(::GithubRepository)
+ singleOf(::RestRepository)
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/di/ViewModelModule.kt b/app/src/main/java/dev/beefers/vendetta/manager/di/ViewModelModule.kt
index 87fa0c0..6f69613 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/di/ViewModelModule.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/di/ViewModelModule.kt
@@ -1,5 +1,6 @@
package dev.beefers.vendetta.manager.di
+import dev.beefers.vendetta.manager.ui.viewmodel.home.HomeViewModel
import dev.beefers.vendetta.manager.ui.viewmodel.installer.InstallerViewModel
import dev.beefers.vendetta.manager.ui.viewmodel.main.MainViewModel
import dev.beefers.vendetta.manager.ui.viewmodel.settings.SettingsViewModel
@@ -10,4 +11,5 @@ val viewModelModule = module {
factoryOf(::InstallerViewModel)
factoryOf(::SettingsViewModel)
factoryOf(::MainViewModel)
+ factoryOf(::HomeViewModel)
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/InstallManager.kt b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/InstallManager.kt
new file mode 100644
index 0000000..2234be2
--- /dev/null
+++ b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/InstallManager.kt
@@ -0,0 +1,66 @@
+package dev.beefers.vendetta.manager.domain.manager
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import dev.beefers.vendetta.manager.installer.service.InstallService
+
+class InstallManager(
+ private val context: Context,
+ private val prefs: PreferenceManager,
+) {
+
+ var current by mutableStateOf(null)
+
+ init {
+ getInstalled()
+ }
+
+ fun getInstalled() {
+ current = try {
+ when {
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
+ context.packageManager.getPackageInfo(
+ prefs.packageName.ifBlank { "dev.beefers.vendetta" },
+ PackageManager.PackageInfoFlags.of(
+ 0L
+ )
+ )
+ }
+
+ else -> {
+ context.packageManager.getPackageInfo(
+ prefs.packageName.ifBlank { "dev.beefers.vendetta" },
+ 0
+ )
+ }
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ null
+ }
+ }
+
+ fun uninstall() {
+ current?.let {
+ val callbackIntent = Intent(context, InstallService::class.java).apply {
+ action = "vendetta.actions.ACTION_UNINSTALL"
+ }
+ val contentIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ PendingIntent.getService(context, 0, callbackIntent, PendingIntent.FLAG_MUTABLE)
+ } else {
+ PendingIntent.getService(context, 0, callbackIntent, 0)
+ }
+
+ context.packageManager.packageInstaller.uninstall(
+ it.packageName,
+ contentIntent.intentSender
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt
index 002d00f..75ff376 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/domain/manager/PreferenceManager.kt
@@ -5,6 +5,7 @@ import android.os.Build
import androidx.annotation.StringRes
import dev.beefers.vendetta.manager.R
import dev.beefers.vendetta.manager.domain.manager.base.BasePreferenceManager
+import dev.beefers.vendetta.manager.utils.DiscordVersion
class PreferenceManager(private val context: Context) :
BasePreferenceManager(context.getSharedPreferences("prefs", Context.MODE_PRIVATE)) {
@@ -25,6 +26,8 @@ class PreferenceManager(private val context: Context) :
var theme by enumPreference("theme", Theme.SYSTEM)
+ var channel by enumPreference("channel", DiscordVersion.Type.STABLE)
+
}
enum class Theme(@StringRes val labelRes: Int) {
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/GithubRepository.kt b/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/GithubRepository.kt
deleted file mode 100644
index 3a0c98e..0000000
--- a/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/GithubRepository.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package dev.beefers.vendetta.manager.domain.repository
-
-import dev.beefers.vendetta.manager.network.service.GithubService
-
-class GithubRepository(
- private val service: GithubService
-) {
-
- suspend fun getLatestRelease() = service.getLatestRelease()
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/RestRepository.kt b/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/RestRepository.kt
new file mode 100644
index 0000000..d433235
--- /dev/null
+++ b/app/src/main/java/dev/beefers/vendetta/manager/domain/repository/RestRepository.kt
@@ -0,0 +1,21 @@
+package dev.beefers.vendetta.manager.domain.repository
+
+import dev.beefers.vendetta.manager.network.service.RestService
+import dev.beefers.vendetta.manager.network.utils.transform
+import dev.beefers.vendetta.manager.utils.DiscordVersion
+
+class RestRepository(
+ private val service: RestService
+) {
+
+ suspend fun getLatestRelease() = service.getLatestRelease()
+
+ suspend fun getLatestDiscordVersions() = service.getLatestDiscordVersions().transform {
+ mapOf(
+ DiscordVersion.Type.ALPHA to DiscordVersion.fromVersionCode(it.latest.alpha),
+ DiscordVersion.Type.BETA to DiscordVersion.fromVersionCode(it.latest.beta),
+ DiscordVersion.Type.STABLE to DiscordVersion.fromVersionCode(it.latest.stable)
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/installer/service/InstallService.kt b/app/src/main/java/dev/beefers/vendetta/manager/installer/service/InstallService.kt
index f27b3ca..8508480 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/installer/service/InstallService.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/installer/service/InstallService.kt
@@ -5,10 +5,17 @@ import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import dev.beefers.vendetta.manager.R
+import dev.beefers.vendetta.manager.domain.manager.InstallManager
import dev.beefers.vendetta.manager.utils.showToast
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+class InstallService : Service(), KoinComponent {
+
+ private val installManager: InstallManager by inject()
-class InstallService : Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ val isInstall = intent.action == "vendetta.actions.ACTION_INSTALL"
when (val statusCode = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
@Suppress("DEPRECATION") // No.
@@ -18,11 +25,15 @@ class InstallService : Service() {
startActivity(confirmationIntent)
}
- PackageInstaller.STATUS_SUCCESS -> showToast(R.string.installer_success)
- PackageInstaller.STATUS_FAILURE_ABORTED -> showToast(R.string.installer_aborted)
+ PackageInstaller.STATUS_SUCCESS -> {
+ if(isInstall) showToast(R.string.installer_success)
+ installManager.getInstalled()
+ }
+
+ PackageInstaller.STATUS_FAILURE_ABORTED -> if(isInstall) showToast(R.string.installer_aborted)
else -> {
- showToast(R.string.installer_failed, statusCode)
+ if(isInstall) showToast(R.string.installer_failed, statusCode)
}
}
@@ -31,4 +42,5 @@ class InstallService : Service() {
}
override fun onBind(intent: Intent): IBinder? = null
+
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/installer/util/PackageInstaller.kt b/app/src/main/java/dev/beefers/vendetta/manager/installer/util/PackageInstaller.kt
index 7ada0d5..dba0f98 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/installer/util/PackageInstaller.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/installer/util/PackageInstaller.kt
@@ -32,7 +32,9 @@ fun Context.installApks(silent: Boolean = false, vararg apks: File) {
}
}
- val callbackIntent = Intent(this, InstallService::class.java)
+ val callbackIntent = Intent(this, InstallService::class.java).apply {
+ action = "vendetta.actions.ACTION_INSTALL"
+ }
@SuppressLint("UnspecifiedImmutableFlag")
val contentIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/network/dto/Index.kt b/app/src/main/java/dev/beefers/vendetta/manager/network/dto/Index.kt
new file mode 100644
index 0000000..8ade0f9
--- /dev/null
+++ b/app/src/main/java/dev/beefers/vendetta/manager/network/dto/Index.kt
@@ -0,0 +1,17 @@
+package dev.beefers.vendetta.manager.network.dto
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Index(
+ val latest: Versions
+) {
+
+ @Serializable
+ data class Versions(
+ val alpha: String,
+ val beta: String,
+ val stable: String
+ )
+
+}
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/network/service/GithubService.kt b/app/src/main/java/dev/beefers/vendetta/manager/network/service/RestService.kt
similarity index 65%
rename from app/src/main/java/dev/beefers/vendetta/manager/network/service/GithubService.kt
rename to app/src/main/java/dev/beefers/vendetta/manager/network/service/RestService.kt
index 13c37df..03dde5e 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/network/service/GithubService.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/network/service/RestService.kt
@@ -1,11 +1,12 @@
package dev.beefers.vendetta.manager.network.service
+import dev.beefers.vendetta.manager.network.dto.Index
import dev.beefers.vendetta.manager.network.dto.Release
import io.ktor.client.request.url
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
-class GithubService(
+class RestService(
private val httpService: HttpService
) {
@@ -15,4 +16,10 @@ class GithubService(
}
}
+ suspend fun getLatestDiscordVersions() = withContext(Dispatchers.IO) {
+ httpService.request {
+ url("https://discord.k6.tf/index.json")
+ }
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/network/utils/ApiResponse.kt b/app/src/main/java/dev/beefers/vendetta/manager/network/utils/ApiResponse.kt
index 51f178b..794e717 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/network/utils/ApiResponse.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/network/utils/ApiResponse.kt
@@ -23,4 +23,13 @@ val ApiResponse.dataOrThrow
inline fun ApiResponse.ifSuccessful(block: (D) -> Unit) {
if (this is ApiResponse.Success) block(data)
-}
\ No newline at end of file
+}
+
+@Suppress("UNCHECKED_CAST")
+fun ApiResponse.transform(block: (T) -> R): ApiResponse {
+ return when (this) {
+ is ApiResponse.Success -> ApiResponse.Success(block(data))
+ is ApiResponse.Error -> this as ApiResponse.Error
+ is ApiResponse.Failure -> this as ApiResponse.Failure
+ }
+}
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/components/SegmentedButton.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/components/SegmentedButton.kt
new file mode 100644
index 0000000..388479d
--- /dev/null
+++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/components/SegmentedButton.kt
@@ -0,0 +1,60 @@
+package dev.beefers.vendetta.manager.ui.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun RowScope.SegmentedButton(
+ icon: Any,
+ iconDescription: String? = null,
+ text: String,
+ onClick: () -> Unit
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically),
+ modifier = Modifier
+ .clickable(onClick = onClick)
+ .background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp))
+ .weight(1f)
+ .padding(16.dp)
+ ) {
+ when (icon) {
+ is ImageVector -> {
+ Icon(
+ imageVector = icon,
+ contentDescription = iconDescription,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+
+ is Painter -> {
+ Icon(
+ painter = icon,
+ contentDescription = iconDescription,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+ }
+
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt
index ead2fc3..3317c6e 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/home/HomeScreen.kt
@@ -1,29 +1,49 @@
package dev.beefers.vendetta.manager.ui.screen.home
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
+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.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Home
+import androidx.compose.material.icons.filled.Info
+import androidx.compose.material.icons.filled.OpenInNew
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material3.Button
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import cafe.adriel.voyager.navigator.tab.TabOptions
import dev.beefers.vendetta.manager.R
+import dev.beefers.vendetta.manager.domain.manager.PreferenceManager
+import dev.beefers.vendetta.manager.ui.components.SegmentedButton
import dev.beefers.vendetta.manager.ui.screen.installer.InstallerScreen
+import dev.beefers.vendetta.manager.ui.viewmodel.home.HomeViewModel
+import dev.beefers.vendetta.manager.utils.DiscordVersion
import dev.beefers.vendetta.manager.utils.ManagerTab
import dev.beefers.vendetta.manager.utils.TabOptions
import dev.beefers.vendetta.manager.utils.navigate
+import org.koin.androidx.compose.get
class HomeScreen : ManagerTab {
override val options: TabOptions
@@ -36,24 +56,105 @@ class HomeScreen : ManagerTab {
@Composable
override fun Content() {
val nav = LocalNavigator.currentOrThrow
+ val prefs: PreferenceManager = get()
+ val viewModel: HomeViewModel = getScreenModel()
+ val iconColor = when {
+ prefs.patchIcon -> Color(0xFF3AB8BA)
+ prefs.channel == DiscordVersion.Type.ALPHA -> Color(0xFFFBB33C)
+ else -> Color(0xFF5865F2)
+ }
Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier
.padding(16.dp)
- .fillMaxSize()
+ .fillMaxWidth()
) {
- Button(
- onClick = { nav.navigate(InstallerScreen()) },
+ Image(
+ painter = painterResource(id = R.drawable.ic_discord_icon),
+ contentDescription = null,
+ modifier = Modifier
+ .size(60.dp)
+ .clip(CircleShape)
+ .background(iconColor)
+ )
+
+ Text(
+ text = prefs.appName,
+ style = MaterialTheme.typography.titleLarge
+ )
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
- Text(stringResource(R.string.action_install))
+ AnimatedVisibility(visible = viewModel.discordVersions != null) {
+ Text(
+ text = "Latest: ${viewModel.discordVersions!![prefs.channel]!!}",
+ style = MaterialTheme.typography.labelLarge,
+ color = LocalContentColor.current.copy(alpha = 0.5f),
+ textAlign = TextAlign.Center
+ )
+ }
+
+ AnimatedVisibility(visible = viewModel.installManager.current != null) {
+ Text(
+ text = "Current: ${viewModel.installManager.current!!.versionName}",
+ style = MaterialTheme.typography.labelLarge,
+ color = LocalContentColor.current.copy(alpha = 0.5f),
+ textAlign = TextAlign.Center
+ )
+ }
}
- Spacer(modifier = Modifier.height(16.dp))
- Text(
- text = "This UI is temporary, check back later for something prettier",
- textAlign = TextAlign.Center,
+
+ Button(
+ onClick = {
+ val version = viewModel.discordVersions!![prefs.channel]!!
+ nav.navigate(InstallerScreen(version))
+ },
+ enabled = viewModel.discordVersions != null,
modifier = Modifier.fillMaxWidth()
- )
+ ) {
+ val label = when {
+ viewModel.installManager.current == null -> R.string.action_install
+ viewModel.installManager.current?.versionName == viewModel.discordVersions?.get(
+ prefs.channel
+ ).toString() -> R.string.action_reinstall
+
+ else -> R.string.action_update
+ }
+ Text(stringResource(label))
+ }
+
+ AnimatedVisibility(visible = viewModel.installManager.current != null) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(2.dp),
+ modifier = Modifier.clip(RoundedCornerShape(16.dp))
+ ) {
+ SegmentedButton(
+ icon = Icons.Filled.OpenInNew,
+ text = stringResource(R.string.action_launch),
+ onClick = { viewModel.launchVendetta() }
+ )
+ SegmentedButton(
+ icon = Icons.Filled.Info,
+ text = stringResource(R.string.action_info),
+ onClick = { viewModel.launchVendettaInfo() }
+ )
+ SegmentedButton(
+ icon = Icons.Filled.Delete,
+ text = stringResource(R.string.action_uninstall),
+ onClick = { viewModel.uninstallVendetta() }
+ )
+ }
+ }
+
+ Column(
+ verticalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+
+ }
}
}
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/installer/InstallerScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/installer/InstallerScreen.kt
index f50b867..69dc962 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/installer/InstallerScreen.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/installer/InstallerScreen.kt
@@ -3,7 +3,9 @@ package dev.beefers.vendetta.manager.ui.screen.installer
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -11,6 +13,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
@@ -32,13 +35,19 @@ import cafe.adriel.voyager.navigator.currentOrThrow
import dev.beefers.vendetta.manager.R
import dev.beefers.vendetta.manager.ui.viewmodel.installer.InstallerViewModel
import dev.beefers.vendetta.manager.ui.widgets.installer.StepGroupCard
+import dev.beefers.vendetta.manager.utils.DiscordVersion
+import org.koin.core.parameter.parametersOf
-class InstallerScreen : Screen {
+class InstallerScreen(
+ val version: DiscordVersion
+) : Screen {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
override fun Content() {
- val viewModel: InstallerViewModel = getScreenModel()
+ val viewModel: InstallerViewModel = getScreenModel {
+ parametersOf(version)
+ }
var expandedGroup by remember {
mutableStateOf(null)
@@ -65,20 +74,33 @@ class InstallerScreen : Screen {
steps = viewModel.getSteps(group),
)
}
+
if (viewModel.isFinished) {
+ Spacer(modifier = Modifier.height(16.dp))
+
+ viewModel.installManager.current?.let {
+ Button(
+ onClick = { viewModel.launchVendetta() },
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(stringResource(R.string.action_launch))
+ }
+ }
+
+ Spacer(modifier = Modifier.height(8.dp))
+
Row(
- horizontalArrangement = Arrangement.spacedBy(16.dp),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.fillMaxWidth()
- .padding(16.dp)
) {
- Button(
+ FilledTonalButton(
onClick = { viewModel.copyDebugInfo() },
modifier = Modifier.weight(1f)
) {
Text(stringResource(R.string.action_copy_logs))
}
- Button(
+ FilledTonalButton(
onClick = { viewModel.clearCache() },
modifier = Modifier.weight(1f)
) {
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt
index 74b138b..7fdb78f 100644
--- a/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt
+++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/screen/settings/SettingsScreen.kt
@@ -79,6 +79,16 @@ class SettingsScreen : ManagerTab {
prefs.patchIcon = it
}
)
+ SettingsItemChoice(
+ label = stringResource(R.string.settings_channel),
+ pref = prefs.channel,
+ labelFactory = {
+ ctx.getString(it.labelRes)
+ },
+ onPrefChange = {
+ prefs.channel = it
+ }
+ )
SettingsButton(
label = stringResource(R.string.action_clear_cache),
diff --git a/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/home/HomeViewModel.kt b/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/home/HomeViewModel.kt
new file mode 100644
index 0000000..e31645d
--- /dev/null
+++ b/app/src/main/java/dev/beefers/vendetta/manager/ui/viewmodel/home/HomeViewModel.kt
@@ -0,0 +1,63 @@
+package dev.beefers.vendetta.manager.ui.viewmodel.home
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.provider.Settings
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import cafe.adriel.voyager.core.model.ScreenModel
+import cafe.adriel.voyager.core.model.coroutineScope
+import dev.beefers.vendetta.manager.domain.manager.InstallManager
+import dev.beefers.vendetta.manager.domain.manager.PreferenceManager
+import dev.beefers.vendetta.manager.domain.repository.RestRepository
+import dev.beefers.vendetta.manager.network.utils.dataOrNull
+import dev.beefers.vendetta.manager.utils.DiscordVersion
+import kotlinx.coroutines.launch
+
+class HomeViewModel(
+ private val repo: RestRepository,
+ val context: Context,
+ val prefs: PreferenceManager,
+ val installManager: InstallManager
+) : ScreenModel {
+
+ var discordVersions by mutableStateOf