add permission support for termux
this will be used in the future
This commit is contained in:
parent
046e3147d9
commit
3ae52c6638
5 changed files with 98 additions and 9 deletions
|
@ -21,7 +21,7 @@ android {
|
|||
}
|
||||
|
||||
// don't forget to add another "s this is counter intuitive I know but not my fault
|
||||
buildConfigField("String", "VASTAI_KEY", "null")
|
||||
buildConfigField("String", "VASTAI_KEY", "\"\"")
|
||||
buildConfigField("String", "VASIAI_API_ENDPOINT", "\"https://cloud.vast.ai/api/v0\"")
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="com.termux.permission.RUN_COMMAND" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package eu.m724.vastapp.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
class PermissionChecker(private val context: Context) {
|
||||
/**
|
||||
* check if the app has a permission
|
||||
* @param permission the permission
|
||||
* @return whether the app has the permission? obviously
|
||||
*/
|
||||
fun hasPermission(permission: String): Boolean {
|
||||
return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a permission exists or if the app is installed
|
||||
* @param permission the permission
|
||||
* @return if the permission exists
|
||||
*/
|
||||
fun permissionExists(permission: String): Boolean {
|
||||
try {
|
||||
context.packageManager.getPermissionInfo(permission, 0)
|
||||
return true
|
||||
} catch (e: NameNotFoundException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permission the permission
|
||||
* @param activity the activity you're calling from
|
||||
* @return if the permission can be asked for, that is if the user didn't check "don't ask again"
|
||||
*/
|
||||
fun canAskForPermission(permission: String, activity: ComponentActivity): Boolean {
|
||||
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
|
||||
}
|
||||
|
||||
/**
|
||||
* request a permission if that permission is not granted
|
||||
* @param permission the permission
|
||||
* @param activity the activity you're calling from
|
||||
* @param callback an Unit, the first boolean is whether the permission is granted and the second one is whether we asked for it
|
||||
*/
|
||||
fun requestIfNoPermission(permission: String, activity: ComponentActivity, callback: (Boolean, Boolean) -> Unit) {
|
||||
val available = canAskForPermission(permission, activity)
|
||||
|
||||
if (hasPermission(permission)) {
|
||||
callback(true, false)
|
||||
} else if (available) { // no permission but can request
|
||||
requestPermission(permission, activity) { callback(it, true) }
|
||||
} else { // no permission and can't request
|
||||
callback(false, false)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should this be private? I mean it doesn't check for other stuff so it's a waste to register an activity if we don't have to
|
||||
private fun requestPermission(permission: String, activity: ComponentActivity, callback: (Boolean) -> Unit) {
|
||||
activity.registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission(),
|
||||
callback
|
||||
).launch(permission)
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ import androidx.activity.enableEdgeToEdge
|
|||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
|
@ -48,7 +47,6 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.Alignment
|
||||
|
@ -65,12 +63,12 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import eu.m724.vastapp.BuildConfig
|
||||
import eu.m724.vastapp.R
|
||||
import eu.m724.vastapp.activity.PermissionChecker
|
||||
import eu.m724.vastapp.activity.dashboard.DashboardActivity
|
||||
import eu.m724.vastapp.ui.theme.VastappTheme
|
||||
import eu.m724.vastapp.vastai.data.User
|
||||
import kotlinx.coroutines.launch
|
||||
import org.chromium.net.CronetEngine
|
||||
import org.w3c.dom.Text
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.random.Random
|
||||
|
||||
|
@ -80,9 +78,30 @@ class LoginActivity : ComponentActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// TODO move this where and run this when we need it
|
||||
val permissionChecker = PermissionChecker(applicationContext)
|
||||
if (!permissionChecker.permissionExists("com.termux.permission.RUN_COMMAND")) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
R.string.no_termux,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
permissionChecker.requestIfNoPermission("com.termux.permission.RUN_COMMAND", this) { granted, asked ->
|
||||
if (granted || !asked) return@requestIfNoPermission
|
||||
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.command_permission_denied),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dashboardLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result -> finish() } // TODO re-login here
|
||||
) { _ -> finish() } // TODO re-login here
|
||||
|
||||
val executor = Executors.newSingleThreadExecutor()
|
||||
val cronetEngine = CronetEngine.Builder(baseContext).build()
|
||||
|
@ -94,7 +113,7 @@ class LoginActivity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch { // TODO I was suggested not to launch an activity from a lifecyclescope
|
||||
lifecycleScope.launch { // TODO I was suggested not to launch an activity from a lifecycle scope
|
||||
loginViewModel.uiState.collect { state ->
|
||||
if (state is LoginUiState.Success) {
|
||||
loadApp(state.user)
|
||||
|
@ -134,12 +153,11 @@ class LoginActivity : ComponentActivity() {
|
|||
|
||||
@Composable
|
||||
fun LoginApp(loginViewModel: LoginViewModel) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val uiState by loginViewModel.uiState.collectAsState()
|
||||
val loginErrorMessage by loginViewModel.error.observeAsState() // TODO put this in uistate
|
||||
val loginErrorMessage by loginViewModel.error.observeAsState() // TODO put this in uiState
|
||||
val isIdle by remember(uiState) { derivedStateOf { uiState !is LoginUiState.Loading } }
|
||||
|
||||
var apiKey by rememberSaveable { mutableStateOf(BuildConfig.VASTAI_KEY ?: "") }
|
||||
var apiKey by rememberSaveable { mutableStateOf(BuildConfig.VASTAI_KEY) }
|
||||
var advancedOpen by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val transition = updateTransition(targetState = advancedOpen, label = "Advanced Menu Transition")
|
||||
|
|
|
@ -20,4 +20,6 @@
|
|||
<string name="login_checkbox_20">having fun?</string>
|
||||
<string name="login_checkbox_angry">checkbox is angry</string>
|
||||
<string name="no_options">none yet sorry</string>
|
||||
<string name="command_permission_denied">If you change your mind, do so from settings</string>
|
||||
<string name="no_termux">Termuxn\'t</string>
|
||||
</resources>
|
Loading…
Reference in a new issue