feat: physical keyboard spark

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2024-12-25 04:59:59 +01:00
parent c1053f0702
commit 666b75dc1d
5 changed files with 153 additions and 6 deletions

View File

@ -1,6 +1,8 @@
package chat.revolt.screens.chat.views.channel package chat.revolt.screens.chat.views.channel
import android.app.Activity
import android.content.ContentValues import android.content.ContentValues
import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
@ -20,6 +22,7 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -44,12 +47,16 @@ import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChip
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
@ -63,6 +70,7 @@ import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallFloatingActionButton import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -84,11 +92,16 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
@ -224,6 +237,12 @@ fun ChannelScreen(
imeInTransition = false imeInTransition = false
} }
} }
LaunchedEffect(Unit) {
if (context.resources.configuration.keyboard and Configuration.KEYBOARD_QWERTY != 0) {
viewModel.usesPhysicalKeyboard()
}
}
// </editor-fold> // </editor-fold>
// <editor-fold desc="Attachment handling"> // <editor-fold desc="Attachment handling">
val processFileUri: (Uri, String?) -> Unit = remember { val processFileUri: (Uri, String?) -> Unit = remember {
@ -831,6 +850,76 @@ fun ChannelScreen(
) )
} }
} }
if (viewModel.showPhysicalKeyboardSpark) {
Card(
modifier = Modifier
.align(Alignment.TopCenter)
.padding(8.dp)
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(16.dp)
) {
Text(
stringResource(R.string.spark_keyboard_shortcuts),
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.SemiBold
)
Text(
buildAnnotatedString {
val raw =
stringResource(R.string.spark_keyboard_shortcuts_description)
val before = raw.substringBefore("%1\$s")
val after = raw.substringAfter("%1\$s")
append(before)
appendInlineContent("metaKey", "Meta")
append(" + /")
append(after)
},
inlineContent = mapOf(
"metaKey" to InlineTextContent(
placeholder = Placeholder(
width = 1.em,
height = 1.em,
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
)
) {
with(LocalDensity.current) {
Image(
painterResource(R.drawable.ic_meta_key_24dp),
contentDescription = null,
/*modifier = Modifier.size(1.em.toDp())*/
)
}
}
),
style = MaterialTheme.typography.bodyLarge
)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
Button(
onClick = {
viewModel.dismissPhysicalKeyboardSpark()
},
modifier = Modifier.weight(1f)
) {
Text(stringResource(R.string.spark_keyboard_shortcuts_dismiss))
}
TextButton(
onClick = {
(context as Activity).requestShowKeyboardShortcuts()
},
modifier = Modifier.weight(1f)
) {
Text(stringResource(R.string.spark_keyboard_shortcuts_cta))
}
}
}
}
}
} }
Column( Column(

View File

@ -872,4 +872,20 @@ class ChannelScreenViewModel @Inject constructor(
items.addAll(groupedItems) items.addAll(groupedItems)
} }
} }
var showPhysicalKeyboardSpark by mutableStateOf(false)
fun usesPhysicalKeyboard() {
viewModelScope.launch {
if (kvStorage.getBoolean("spark/physicalKeyboard/dismissed") != true) {
showPhysicalKeyboardSpark = true
}
}
}
fun dismissPhysicalKeyboardSpark() {
viewModelScope.launch {
kvStorage.set("spark/physicalKeyboard/dismissed", true)
showPhysicalKeyboardSpark = false
}
}
} }

View File

@ -18,6 +18,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ElevatedButton import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
@ -66,8 +67,13 @@ class DebugSettingsScreenViewModel @Inject constructor(
private val kvStorage: KVStorage private val kvStorage: KVStorage
) : ViewModel() { ) : ViewModel() {
fun forgetAllSparks() { fun forgetAllSparks() {
// No op because there are no active sparks forgetPhysicalKeyboardSpark()
// psst, notifications will be the next one }
fun forgetPhysicalKeyboardSpark() {
viewModelScope.launch {
kvStorage.remove("spark/physicalKeyboard/dismissed")
}
} }
fun forgetLatestChangelog() { fun forgetLatestChangelog() {
@ -209,10 +215,11 @@ fun DebugSettingsScreen(
Row( Row(
modifier = Modifier.horizontalScroll(rememberScrollState()) modifier = Modifier.horizontalScroll(rememberScrollState())
) { ) {
ElevatedButton(onClick = { viewModel.forgetPhysicalKeyboardSpark() }) {
Text("There are no active sparks, but you can still try to ") Text("Forget physical keyboard spark")
ElevatedButton(onClick = { viewModel.forgetAllSparks() }) { }
Text("forget all sparks") Button(onClick = { viewModel.forgetAllSparks() }) {
Text("Forget all sparks")
} }
} }

View File

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!--
~ Copyright (C) 2016 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<path
android:pathData="M5.5,5.5m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
android:fillColor="#ffffff" />
<path
android:pathData="M5.5,16.5m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
android:fillColor="#ffffff" />
<path
android:pathData="M16.5,5.5m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
android:fillColor="#ffffff" />
<path
android:pathData="M18.5,16.5C18.5,15.4 17.6,14.5 16.5,14.5C15.4,14.5 14.5,15.4 14.5,16.5C14.5,17.6 15.4,18.5 16.5,18.5C17.6,18.5 18.5,17.6 18.5,16.5ZM12.5,16.5C12.5,14.29 14.29,12.5 16.5,12.5C18.71,12.5 20.5,14.29 20.5,16.5C20.5,17.241 20.299,17.934 19.948,18.529L23,21.59L21.59,23L18.529,19.948C17.934,20.299 17.241,20.5 16.5,20.5C14.29,20.5 12.5,18.71 12.5,16.5Z"
android:fillColor="#ffffff"
android:fillType="evenOdd" />
</vector>

View File

@ -577,6 +577,7 @@
<string name="spark_keyboard_shortcuts">Using a keyboard?</string> <string name="spark_keyboard_shortcuts">Using a keyboard?</string>
<string name="spark_keyboard_shortcuts_description">Revolt has keyboard shortcuts! Press %1$s to see them.</string> <string name="spark_keyboard_shortcuts_description">Revolt has keyboard shortcuts! Press %1$s to see them.</string>
<string name="spark_keyboard_shortcuts_cta">Open shortcuts</string> <string name="spark_keyboard_shortcuts_cta">Open shortcuts</string>
<string name="spark_keyboard_shortcuts_dismiss">Alright</string>
<string name="notice_platform_mod_dm_title">Important notice regarding your account</string> <string name="notice_platform_mod_dm_title">Important notice regarding your account</string>
<string name="notice_platform_mod_dm_description">You have received an important notice regarding your account from our moderation team. Please read it carefully.</string> <string name="notice_platform_mod_dm_description">You have received an important notice regarding your account from our moderation team. Please read it carefully.</string>