mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-03 13:14:46 +00:00
compose welcome wizard (could look better, but good enough for now)
This commit is contained in:
parent
b65d00e142
commit
247ec2b7f3
3 changed files with 233 additions and 3 deletions
|
@ -20,9 +20,9 @@ public final class SetupActivity extends Activity {
|
|||
super.onCreate(savedInstanceState);
|
||||
final Intent intent = new Intent();
|
||||
final InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
|
||||
if (UncachedInputMethodManagerUtils.isThisImeCurrent(this, imm))
|
||||
// if (UncachedInputMethodManagerUtils.isThisImeCurrent(this, imm))
|
||||
intent.setClass(this, SettingsActivity.class);
|
||||
else intent.setClass(this, SetupWizardActivity.class);
|
||||
// else intent.setClass(this, SetupWizardActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
package helium314.keyboard.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
|
@ -8,6 +9,7 @@ import android.os.Build
|
|||
import android.os.Bundle
|
||||
import android.view.WindowInsets.Type
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -15,6 +17,9 @@ import androidx.compose.material3.Surface
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isGone
|
||||
|
@ -26,6 +31,7 @@ import helium314.keyboard.latin.common.FileUtils
|
|||
import helium314.keyboard.latin.define.DebugFlags
|
||||
import helium314.keyboard.latin.settings.Settings
|
||||
import helium314.keyboard.latin.utils.ExecutorUtils
|
||||
import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils
|
||||
import helium314.keyboard.latin.utils.cleanUnusedMainDicts
|
||||
import helium314.keyboard.latin.utils.prefs
|
||||
import helium314.keyboard.settings.dialogs.ConfirmationDialog
|
||||
|
@ -50,6 +56,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
|
|||
private val dictUriFlow = MutableStateFlow<Uri?>(null)
|
||||
private val cachedDictionaryFile by lazy { File(this.cacheDir.path + File.separator + "temp_dict") }
|
||||
private val crashReportFiles = MutableStateFlow<List<File>>(emptyList())
|
||||
private var paused = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -60,6 +67,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
|
|||
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { cleanUnusedMainDicts(this) }
|
||||
if (BuildConfig.DEBUG || DebugFlags.DEBUG_ENABLED)
|
||||
crashReportFiles.value = findCrashReports()
|
||||
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
// with this the layout edit dialog is not covered by the keyboard
|
||||
// alternative of Modifier.imePadding() and properties = DialogProperties(decorFitsSystemWindows = false) has other weird side effects
|
||||
|
@ -89,6 +97,10 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
|
|||
val dictUri by dictUriFlow.collectAsState()
|
||||
val crashReports by crashReportFiles.collectAsState()
|
||||
val crashFilePicker = filePicker { saveCrashReports(it) }
|
||||
var showWelcomeWizard by rememberSaveable { mutableStateOf(
|
||||
!UncachedInputMethodManagerUtils.isThisImeCurrent(this, imm)
|
||||
|| !UncachedInputMethodManagerUtils.isThisImeEnabled(this, imm)
|
||||
) }
|
||||
if (spellchecker)
|
||||
Column { // lazy way of implementing spell checker settings
|
||||
settingsContainer[Settings.PREF_USE_CONTACTS]!!.Preference()
|
||||
|
@ -127,6 +139,9 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
|
|||
content = { Text("Crash report files found") },
|
||||
)
|
||||
}
|
||||
if (showWelcomeWizard) {
|
||||
WelcomeWizard(close = { showWelcomeWizard = false }, finish = this::finish)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +183,6 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
|
|||
paused = false
|
||||
}
|
||||
|
||||
private var paused = true
|
||||
fun setForceTheme(theme: String?, night: Boolean?) {
|
||||
if (paused) return
|
||||
if (forceTheme != theme || forceNight != night) {
|
||||
|
|
216
app/src/main/java/helium314/keyboard/settings/WelcomeWizard.kt
Normal file
216
app/src/main/java/helium314/keyboard/settings/WelcomeWizard.kt
Normal file
|
@ -0,0 +1,216 @@
|
|||
package helium314.keyboard.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import helium314.keyboard.latin.R
|
||||
import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun WelcomeWizard(
|
||||
close: () -> Unit,
|
||||
finish: () -> Unit
|
||||
) {
|
||||
val ctx = LocalContext.current
|
||||
val width = LocalConfiguration.current.screenWidthDp
|
||||
val height = LocalConfiguration.current.screenHeightDp
|
||||
val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
fun determineStep(): Int = when {
|
||||
!UncachedInputMethodManagerUtils.isThisImeEnabled(ctx, imm) -> 0
|
||||
!UncachedInputMethodManagerUtils.isThisImeCurrent(ctx, imm) -> 2
|
||||
else -> 3
|
||||
}
|
||||
var step by rememberSaveable { mutableIntStateOf(determineStep()) }
|
||||
val scope = rememberCoroutineScope()
|
||||
LaunchedEffect(step) {
|
||||
if (step == 2)
|
||||
scope.launch {
|
||||
while (step == 2 && !UncachedInputMethodManagerUtils.isThisImeCurrent(ctx, imm)) {
|
||||
delay(200)
|
||||
}
|
||||
step = 3
|
||||
}
|
||||
}
|
||||
val useWideLayout = height < 500 && width > height
|
||||
val appName = stringResource(ctx.applicationInfo.labelRes)
|
||||
@Composable fun bigText() {
|
||||
val resource = if (step == 0) R.string.setup_welcome_title else R.string.setup_steps_title
|
||||
Text(
|
||||
stringResource(resource, appName),
|
||||
style = MaterialTheme.typography.displayMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(bottom = 36.dp)
|
||||
)
|
||||
}
|
||||
@Composable fun steps() {
|
||||
if (step == 0)
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Image(painterResource(R.drawable.setup_welcome_image), null)
|
||||
Row(Modifier.clickable { step = 1 }
|
||||
.padding(top = 4.dp, start = 4.dp, end = 4.dp)
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Text(
|
||||
stringResource(R.string.setup_start_action),
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
else
|
||||
Column {
|
||||
val title: String
|
||||
val instruction: String
|
||||
val icon: Painter
|
||||
val actionText: String
|
||||
val action: () -> Unit
|
||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
step = determineStep()
|
||||
}
|
||||
if (step == 1) {
|
||||
title = stringResource(R.string.setup_step1_title, appName)
|
||||
instruction = stringResource(R.string.setup_step1_instruction, appName)
|
||||
icon = painterResource(R.drawable.ic_setup_key)
|
||||
actionText = stringResource(R.string.setup_step1_action)
|
||||
action = {
|
||||
val intent = Intent()
|
||||
intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS)
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
launcher.launch(intent)
|
||||
}
|
||||
} else if (step == 2) {
|
||||
title = stringResource(R.string.setup_step2_title, appName)
|
||||
instruction = stringResource(R.string.setup_step2_instruction, appName)
|
||||
icon = painterResource(R.drawable.ic_setup_select)
|
||||
actionText = stringResource(R.string.setup_step2_action)
|
||||
action = imm::showInputMethodPicker
|
||||
} else { // step 3
|
||||
title = stringResource(R.string.setup_step3_title)
|
||||
instruction = stringResource(R.string.setup_step3_instruction, appName)
|
||||
icon = painterResource(R.drawable.sym_keyboard_language_switch)
|
||||
actionText = stringResource(R.string.setup_step3_action)
|
||||
action = close
|
||||
}
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text("1", color = if (step == 1) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onPrimary)
|
||||
Text("2", color = if (step == 2) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onPrimary)
|
||||
Text("3", color = if (step == 3) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onPrimary)
|
||||
}
|
||||
Column(Modifier
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
Text(title)
|
||||
Text(instruction, style = MaterialTheme.typography.bodyLarge.merge(color = MaterialTheme.colorScheme.onPrimary))
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Row(
|
||||
Modifier.clickable { action() }
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
.padding(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(icon, null, Modifier.padding(end = 6.dp).size(32.dp), tint = MaterialTheme.colorScheme.onPrimary)
|
||||
Text(actionText, Modifier.weight(1f))
|
||||
}
|
||||
if (step == 3) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Row(
|
||||
Modifier.clickable { finish() }
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
.padding(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_setup_check),
|
||||
null,
|
||||
Modifier.padding(end = 6.dp).size(32.dp),
|
||||
tint = MaterialTheme.colorScheme.onPrimary
|
||||
)
|
||||
Text(stringResource(R.string.setup_finish_action), Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Surface {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.primary,
|
||||
LocalTextStyle provides MaterialTheme.typography.titleLarge.merge(color = MaterialTheme.colorScheme.onPrimary),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().padding(32.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (useWideLayout)
|
||||
Row {
|
||||
Box(Modifier.weight(0.4f)) {
|
||||
bigText()
|
||||
}
|
||||
Box(Modifier.weight(0.6f)) {
|
||||
steps()
|
||||
}
|
||||
}
|
||||
else
|
||||
Column {
|
||||
bigText()
|
||||
steps()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
// content cut off on real device, but not here... great?
|
||||
device = "spec:orientation=landscape,width=400dp,height=780dp"
|
||||
)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
Theme(true) {
|
||||
Surface {
|
||||
WelcomeWizard({}) { }
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue