[feat] Optional self signed certificate
This commit is contained in:
@@ -3,7 +3,9 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
kotlin("plugin.serialization") version "1.9.0"
|
||||
id("kotlin-kapt")
|
||||
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.hilt.android)
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -31,11 +33,11 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
jvmTarget = "21"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
@@ -43,9 +45,14 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.hilt.android)
|
||||
implementation(libs.hilt.navigation.compose)
|
||||
ksp(libs.hilt.android.compiler)
|
||||
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
kapt("androidx.room:room-compiler:2.7.2")
|
||||
ksp(libs.androidx.room.compiler)
|
||||
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.bcprov.jdk15on)
|
||||
implementation(libs.converter.gson)
|
||||
|
||||
@@ -5,9 +5,11 @@ import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "configure")
|
||||
|
||||
@HiltAndroidApp
|
||||
class AetherApp : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
@@ -55,10 +55,17 @@ import com.acitelight.aether.view.HomeScreen
|
||||
import com.acitelight.aether.view.MeScreen
|
||||
import com.acitelight.aether.view.VideoPlayer
|
||||
import com.acitelight.aether.view.VideoScreen
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
window.attributes = window.attributes.apply {
|
||||
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
|
||||
package com.acitelight.aether.service
|
||||
|
||||
import android.content.Context
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.CertificatePinner
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.InetAddress
|
||||
import java.net.URL
|
||||
import java.security.KeyStore
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import okhttp3.EventListener
|
||||
import java.net.InetAddress
|
||||
import android.util.Log
|
||||
import okhttp3.ConnectionSpec
|
||||
|
||||
object ApiClient {
|
||||
var base: String = ""
|
||||
@@ -34,6 +31,14 @@ object ApiClient {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
private val dnsEventListener = object : EventListener() {
|
||||
override fun dnsEnd(call: okhttp3.Call, domainName: String, inetAddressList: List<InetAddress>) {
|
||||
super.dnsEnd(call, domainName, inetAddressList)
|
||||
val ipAddresses = inetAddressList.joinToString(", ") { it.hostAddress }
|
||||
Log.d("OkHttp_DNS", "Domain '$domainName' resolved to IPs: [$ipAddresses]")
|
||||
}
|
||||
}
|
||||
|
||||
fun loadCertificateFromString(pemString: String): X509Certificate {
|
||||
val certificateFactory = CertificateFactory.getInstance("X.509")
|
||||
val decodedPem = pemString
|
||||
@@ -108,6 +113,7 @@ object ApiClient {
|
||||
}
|
||||
|
||||
return OkHttpClient.Builder()
|
||||
.connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS))
|
||||
.sslSocketFactory(sslContext.socketFactory, combinedTm)
|
||||
.build()
|
||||
|
||||
@@ -116,13 +122,20 @@ object ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
fun createOkHttp(cert: String?): OkHttpClient {
|
||||
val trustedCert = cert?.let { loadCertificateFromString(it) }
|
||||
return createOkHttpClientWithDynamicCert(trustedCert)
|
||||
fun createOkHttp(): OkHttpClient {
|
||||
return if (cert == "")
|
||||
OkHttpClient
|
||||
.Builder()
|
||||
.connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS))
|
||||
.eventListener(dnsEventListener)
|
||||
.build()
|
||||
else
|
||||
createOkHttpClientWithDynamicCert(loadCertificateFromString(cert))
|
||||
|
||||
}
|
||||
|
||||
private fun createRetrofit(): Retrofit {
|
||||
val okHttpClient = createOkHttpClientWithDynamicCert(loadCertificateFromString(cert))
|
||||
val okHttpClient = createOkHttp()
|
||||
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(base)
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
package com.acitelight.aether.service
|
||||
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import com.acitelight.aether.model.ChallengeResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Call
|
||||
import okhttp3.EventListener
|
||||
import okhttp3.Handshake
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters
|
||||
import org.bouncycastle.crypto.signers.Ed25519Signer
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.Proxy
|
||||
import java.net.InetSocketAddress
|
||||
import java.security.PrivateKey
|
||||
import java.security.Signature
|
||||
|
||||
@@ -17,13 +28,13 @@ object AuthManager {
|
||||
challengeBase64 = api!!.getChallenge(username).string()
|
||||
}catch (e: Exception)
|
||||
{
|
||||
print(e.message)
|
||||
return null
|
||||
}
|
||||
|
||||
val signedBase64 = signChallenge(db64(privateKey), db64(challengeBase64))
|
||||
|
||||
return try {
|
||||
api!!.verifyChallenge(username, ChallengeResponse(response = signedBase64)).string()
|
||||
api.verifyChallenge(username, ChallengeResponse(response = signedBase64)).string()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.acitelight.aether.service
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
|
||||
@Singleton
|
||||
class SettingsDataStoreManager @Inject constructor(
|
||||
@ApplicationContext private val context: Context
|
||||
) {
|
||||
companion object {
|
||||
val USER_NAME_KEY = stringPreferencesKey("user_name")
|
||||
val PRIVATE_KEY = stringPreferencesKey("private_key")
|
||||
val URL_KEY = stringPreferencesKey("url")
|
||||
val CERT_KEY = stringPreferencesKey("cert")
|
||||
val USE_SELF_SIGNED_KEY = booleanPreferencesKey("use_self_signed")
|
||||
}
|
||||
|
||||
val userNameFlow: Flow<String> = context.dataStore.data.map { preferences ->
|
||||
preferences[USER_NAME_KEY] ?: ""
|
||||
}
|
||||
|
||||
val privateKeyFlow: Flow<String> = context.dataStore.data.map { preferences ->
|
||||
preferences[PRIVATE_KEY] ?: ""
|
||||
}
|
||||
|
||||
val urlFlow: Flow<String> = context.dataStore.data.map { preferences ->
|
||||
preferences[URL_KEY] ?: ""
|
||||
}
|
||||
|
||||
val certFlow: Flow<String> = context.dataStore.data.map { preferences ->
|
||||
preferences[CERT_KEY] ?: ""
|
||||
}
|
||||
|
||||
val useSelfSignedFlow: Flow<Boolean> = context.dataStore.data.map { preferences ->
|
||||
preferences[USE_SELF_SIGNED_KEY] ?: false
|
||||
}
|
||||
|
||||
suspend fun saveUserName(name: String) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[USER_NAME_KEY] = name
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun savePrivateKey(key: String) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[PRIVATE_KEY] = key
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveUrl(url: String) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[URL_KEY] = url
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveCert(cert: String) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[CERT_KEY] = cert
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveUseSelfSigned(useSelfSigned: Boolean) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[USE_SELF_SIGNED_KEY] = useSelfSigned
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun clearAll() {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.acitelight.aether.Global
|
||||
@@ -30,7 +31,7 @@ import com.acitelight.aether.service.RecentManager
|
||||
import com.acitelight.aether.viewModel.HomeScreenViewModel
|
||||
|
||||
@Composable
|
||||
fun HomeScreen(homeScreenViewModel: HomeScreenViewModel = viewModel(), navController: NavController)
|
||||
fun HomeScreen(homeScreenViewModel: HomeScreenViewModel = hiltViewModel(), navController: NavController)
|
||||
{
|
||||
if(Global.loggedIn)
|
||||
homeScreenViewModel.Init()
|
||||
|
||||
@@ -3,11 +3,13 @@ package com.acitelight.aether.view
|
||||
import android.widget.Toast
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -17,6 +19,7 @@ import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
@@ -32,17 +35,20 @@ import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.acitelight.aether.viewModel.MeScreenViewModel
|
||||
|
||||
@Composable
|
||||
fun MeScreen(meScreenViewModel: MeScreenViewModel = viewModel()) {
|
||||
fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel()) {
|
||||
val context = LocalContext.current
|
||||
var username by meScreenViewModel.username;
|
||||
var privateKey by meScreenViewModel.privateKey;
|
||||
var url by meScreenViewModel.url
|
||||
var cert by meScreenViewModel.cert
|
||||
|
||||
val uss by meScreenViewModel.uss.collectAsState(initial = false)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -134,6 +140,8 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = viewModel()) {
|
||||
.align(Alignment.Start)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// Username input field
|
||||
OutlinedTextField(
|
||||
value = url,
|
||||
@@ -146,21 +154,37 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = viewModel()) {
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
// Private key input field
|
||||
OutlinedTextField(
|
||||
value = cert,
|
||||
onValueChange = { cert = it },
|
||||
label = { Text("Cert") },
|
||||
singleLine = false,
|
||||
maxLines = 40,
|
||||
minLines = 20,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = TextStyle(
|
||||
fontSize = 8.sp
|
||||
Row(Modifier.align(Alignment.Start)) {
|
||||
Checkbox(
|
||||
checked = uss,
|
||||
onCheckedChange = { isChecked ->
|
||||
meScreenViewModel.onUseSelfSignedCheckedChange(isChecked)
|
||||
},
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "Use Self-Signed Cert",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
// Private key input field
|
||||
if (uss)
|
||||
OutlinedTextField(
|
||||
value = cert,
|
||||
onValueChange = { cert = it },
|
||||
label = { Text("Cert") },
|
||||
singleLine = false,
|
||||
maxLines = 40,
|
||||
minLines = 20,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = TextStyle(
|
||||
fontSize = 8.sp
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
|
||||
@@ -31,33 +31,19 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.acitelight.aether.service.*
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
||||
class HomeScreenViewModel(application: Application) : AndroidViewModel(application)
|
||||
|
||||
@HiltViewModel
|
||||
class HomeScreenViewModel @Inject constructor(
|
||||
private val settingsDataStoreManager: SettingsDataStoreManager
|
||||
) : ViewModel()
|
||||
{
|
||||
private val dataStore = application.dataStore
|
||||
private val USER_NAME_KEY = stringPreferencesKey("user_name")
|
||||
private val PRIVATE_KEY = stringPreferencesKey("private_key")
|
||||
private val URL_KEY = stringPreferencesKey("url")
|
||||
private val CERT_KEY = stringPreferencesKey("cert")
|
||||
|
||||
val userNameFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[USER_NAME_KEY] ?: ""
|
||||
}
|
||||
|
||||
val privateKeyFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[PRIVATE_KEY] ?: ""
|
||||
}
|
||||
|
||||
val urlFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[URL_KEY] ?: ""
|
||||
}
|
||||
|
||||
val certFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[CERT_KEY] ?: ""
|
||||
}
|
||||
|
||||
var _init = false
|
||||
var imageLoader: ImageLoader? = null;
|
||||
val uss = settingsDataStoreManager.useSelfSignedFlow
|
||||
|
||||
@Composable
|
||||
fun Init(){
|
||||
@@ -79,15 +65,15 @@ class HomeScreenViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
val u = userNameFlow.first()
|
||||
val p = privateKeyFlow.first()
|
||||
val ur = urlFlow.first()
|
||||
val c = certFlow.first()
|
||||
val u = settingsDataStoreManager.userNameFlow.first()
|
||||
val p = settingsDataStoreManager.privateKeyFlow.first()
|
||||
val ur = settingsDataStoreManager.urlFlow.first()
|
||||
val c = settingsDataStoreManager.certFlow.first()
|
||||
|
||||
if(u=="" || p=="" || ur=="" || c=="") return@launch
|
||||
if(u=="" || p=="" || ur=="") return@launch
|
||||
|
||||
try{
|
||||
val usedUrl = ApiClient.apply(ur, c)
|
||||
val usedUrl = ApiClient.apply(ur, if(uss.first()) c else "")
|
||||
|
||||
if (MediaManager.token == "null")
|
||||
MediaManager.token = AuthManager.fetchToken(
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.acitelight.aether.Global
|
||||
import com.acitelight.aether.dataStore
|
||||
@@ -20,63 +21,52 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.acitelight.aether.service.*
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
||||
class MeScreenViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val dataStore = application.dataStore
|
||||
private val USER_NAME_KEY = stringPreferencesKey("user_name")
|
||||
private val PRIVATE_KEY = stringPreferencesKey("private_key")
|
||||
private val URL_KEY = stringPreferencesKey("url")
|
||||
private val CERT_KEY = stringPreferencesKey("cert")
|
||||
|
||||
val userNameFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[USER_NAME_KEY] ?: ""
|
||||
}
|
||||
|
||||
val privateKeyFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[PRIVATE_KEY] ?: ""
|
||||
}
|
||||
|
||||
val urlFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[URL_KEY] ?: ""
|
||||
}
|
||||
|
||||
val certFlow: Flow<String> = dataStore.data.map { preferences ->
|
||||
preferences[CERT_KEY] ?: ""
|
||||
}
|
||||
@HiltViewModel
|
||||
class MeScreenViewModel @Inject constructor(
|
||||
private val settingsDataStoreManager: SettingsDataStoreManager
|
||||
) : ViewModel() {
|
||||
|
||||
val username = mutableStateOf("");
|
||||
val privateKey = mutableStateOf("")
|
||||
val url = mutableStateOf("");
|
||||
val cert = mutableStateOf("")
|
||||
|
||||
val uss = settingsDataStoreManager.useSelfSignedFlow
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
username.value = userNameFlow.first()
|
||||
privateKey.value = if (privateKeyFlow.first() == "") "" else "******"
|
||||
url.value = urlFlow.first()
|
||||
cert.value = certFlow.first()
|
||||
username.value = settingsDataStoreManager.userNameFlow.first()
|
||||
privateKey.value = if (settingsDataStoreManager.privateKeyFlow.first() == "") "" else "******"
|
||||
url.value = settingsDataStoreManager.urlFlow.first()
|
||||
cert.value = settingsDataStoreManager.certFlow.first()
|
||||
}
|
||||
}
|
||||
|
||||
fun onUseSelfSignedCheckedChange(isChecked: Boolean) {
|
||||
viewModelScope.launch {
|
||||
settingsDataStoreManager.saveUseSelfSigned(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateServer(u: String, c: String, context: Context)
|
||||
{
|
||||
viewModelScope.launch {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[URL_KEY] = u
|
||||
preferences[CERT_KEY] = c
|
||||
}
|
||||
settingsDataStoreManager.saveUrl(u)
|
||||
settingsDataStoreManager.saveCert(c)
|
||||
|
||||
Global.loggedIn = false
|
||||
|
||||
val us = userNameFlow.first()
|
||||
val u = urlFlow.first()
|
||||
val c = certFlow.first()
|
||||
val p = privateKeyFlow.first()
|
||||
val us = settingsDataStoreManager.userNameFlow.first()
|
||||
val p = settingsDataStoreManager.privateKeyFlow.first()
|
||||
|
||||
if (u == "" || c == "" || p == "" || us == "") return@launch
|
||||
if (u == "" || p == "" || us == "") return@launch
|
||||
|
||||
try {
|
||||
val usedUrl = ApiClient.apply(u, c)
|
||||
val usedUrl = ApiClient.apply(u, if(uss.first()) c else "")
|
||||
MediaManager.token = AuthManager.fetchToken(
|
||||
us,
|
||||
p
|
||||
@@ -93,22 +83,18 @@ class MeScreenViewModel(application: Application) : AndroidViewModel(application
|
||||
|
||||
fun updateAccount(u: String, p: String, context: Context) {
|
||||
viewModelScope.launch {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[USER_NAME_KEY] = u
|
||||
preferences[PRIVATE_KEY] = p
|
||||
}
|
||||
settingsDataStoreManager.saveUserName(u)
|
||||
settingsDataStoreManager.savePrivateKey(p)
|
||||
|
||||
privateKey.value = "******"
|
||||
|
||||
Global.loggedIn = false
|
||||
|
||||
val u = userNameFlow.first()
|
||||
val p = privateKeyFlow.first()
|
||||
val u = settingsDataStoreManager.userNameFlow.first()
|
||||
val p = settingsDataStoreManager.privateKeyFlow.first()
|
||||
val ur = settingsDataStoreManager.urlFlow.first()
|
||||
|
||||
val ur = urlFlow.first()
|
||||
val c = certFlow.first()
|
||||
|
||||
if (u == "" || p == "" || ur == "" || c == "") return@launch
|
||||
if (u == "" || p == "" || ur == "") return@launch
|
||||
|
||||
try {
|
||||
MediaManager.token = AuthManager.fetchToken(
|
||||
|
||||
@@ -3,4 +3,7 @@ plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.compose) apply false
|
||||
|
||||
alias(libs.plugins.hilt.android) apply false
|
||||
alias(libs.plugins.ksp) apply false
|
||||
}
|
||||
@@ -8,15 +8,15 @@ converterGson = "3.0.0"
|
||||
datastorePreferences = "1.1.7"
|
||||
exoplayerplus = "0.2.0"
|
||||
gson = "2.13.1"
|
||||
kotlin = "2.2.10"
|
||||
kotlin = "2.2.20"
|
||||
coreKtx = "1.17.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.3.0"
|
||||
espressoCore = "3.7.0"
|
||||
kotlinxSerializationJson = "1.9.0"
|
||||
lifecycleRuntimeKtx = "2.9.2"
|
||||
lifecycleRuntimeKtx = "2.9.3"
|
||||
activityCompose = "1.10.1"
|
||||
composeBom = "2025.08.00"
|
||||
composeBom = "2025.08.01"
|
||||
media3Common = "1.8.0"
|
||||
media3Exoplayer = "1.8.0"
|
||||
media3Ui = "1.8.0"
|
||||
@@ -29,6 +29,10 @@ roomCompiler = "2.7.2"
|
||||
roomKtx = "2.7.2"
|
||||
roomRuntime = "2.7.2"
|
||||
|
||||
ksp = "2.1.21-2.0.2"
|
||||
hilt = "2.57.1"
|
||||
hilt-navigation-compose = "1.2.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||
@@ -64,8 +68,14 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit
|
||||
retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit2KotlinxSerializationConverter" }
|
||||
androidx-media3-datasource-okhttp = { group = "androidx.media3", name = "media3-datasource-okhttp", version.ref = "media3DatasourceOkhttp" }
|
||||
|
||||
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
||||
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
|
||||
hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-navigation-compose" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
||||
Reference in New Issue
Block a user