Skip to content

Commit

Permalink
Decrease ToolBar height from 60 to 56; Re-implement CandidateView; Im…
Browse files Browse the repository at this point in the history
…plement RemoveCandidateFromMemory
  • Loading branch information
bingzheung committed Jan 1, 2025
1 parent fa41bb8 commit c491f13
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ class JyutpingInputMethodService: LifecycleInputMethodService(),

private val selectedCandidates: MutableList<Candidate> by lazy { mutableListOf() }
private val userDB by lazy { UserLexiconHelper(this) }
fun forgetCandidate(candidate: Candidate) {
userDB.remove(candidate)
}
fun clearUserLexicon() {
userDB.deleteAll()
}
Expand Down Expand Up @@ -610,8 +613,7 @@ class JyutpingInputMethodService: LifecycleInputMethodService(),
currentInputConnection.commitText(text, 1)
adjustKeyboardCase()
}
fun selectCandidate(candidate: Candidate? = null, index: Int = 0) {
val candidate: Candidate = candidate ?: candidates.value.getOrNull(index) ?: return
fun selectCandidate(candidate: Candidate) {
currentInputConnection.commitText(candidate.text, 1)
selectedCandidates.add(candidate)
val firstChar = bufferText.firstOrNull()
Expand Down Expand Up @@ -708,7 +710,7 @@ class JyutpingInputMethodService: LifecycleInputMethodService(),
fun space() {
if (isBuffering.value) {
if (candidates.value.isNotEmpty()) {
selectCandidate()
candidates.value.firstOrNull()?.let { selectCandidate(it) }
} else {
currentInputConnection.commitText(bufferText, 1)
bufferText = PresetString.EMPTY
Expand Down
25 changes: 11 additions & 14 deletions app/src/main/java/org/jyutping/jyutping/keyboard/CandidateBoard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import android.view.HapticFeedbackConstants
import android.view.SoundEffectConstants
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
Expand All @@ -30,7 +28,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -62,11 +59,14 @@ private class CandidateRow(val identifier: Int, val candidates: List<Candidate>,
fun CandidateBoard(height: Dp) {
val collapseWidth: Dp = 44.dp
val collapseHeight: Dp = 44.dp
val interactionSource = remember { MutableInteractionSource() }
val view = LocalView.current
val context = LocalContext.current as JyutpingInputMethodService
val commentStyle by context.commentStyle.collectAsState()
val rowVerticalAlignment: Alignment.Vertical = if (commentStyle.isBelow()) Alignment.Top else Alignment.Bottom
val rowVerticalAlignment: Alignment.Vertical = when (commentStyle) {
CommentStyle.AboveCandidates -> Alignment.Bottom
CommentStyle.BelowCandidates -> Alignment.Top
CommentStyle.NoComments -> Alignment.CenterVertically
}
val isDarkMode by context.isDarkMode.collectAsState()
val isHighContrastPreferred by context.isHighContrastPreferred.collectAsState()
val extraBottomPadding by context.extraBottomPadding.collectAsState()
Expand Down Expand Up @@ -137,18 +137,15 @@ fun CandidateBoard(height: Dp) {
verticalAlignment = rowVerticalAlignment
) {
row.candidates.map {
CandidateView(
AltCandidateView(
modifier = Modifier
.padding(2.dp)
.weight(it.width() / row.width),
candidate = it,
commentStyle = commentStyle,
isDarkMode = isDarkMode,
modifier = Modifier
.clickable(interactionSource = interactionSource, indication = null) {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
context.selectCandidate(it)
}
.padding(2.dp)
.weight(it.width() / row.width)
selection = { context.selectCandidate(it) },
deletion = { context.forgetCandidate(it) }
)
}
if (row.identifier == minRowIdentifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@ package org.jyutping.jyutping.keyboard
import android.view.HapticFeedbackConstants
import android.view.SoundEffectConstants
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
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.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand All @@ -24,7 +21,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand All @@ -42,25 +38,9 @@ import org.jyutping.jyutping.presets.PresetColor
fun CandidateScrollBar() {
val expanderWidth: Dp = 44.dp
val dividerHeight: Dp = 24.dp
val interactionSource = remember { MutableInteractionSource() }
val view = LocalView.current
val context = LocalContext.current as JyutpingInputMethodService
val commentStyle by context.commentStyle.collectAsState()
val candidateViewTopInset: Dp = when (commentStyle) {
CommentStyle.AboveCandidates -> 0.dp
CommentStyle.BelowCandidates -> 4.dp
CommentStyle.NoComments -> 0.dp
}
val candidateViewBottomInset: Dp = when (commentStyle) {
CommentStyle.AboveCandidates -> 12.dp
CommentStyle.BelowCandidates -> 0.dp
CommentStyle.NoComments -> 16.dp
}
val candidateRowVerticalAlignment: Alignment.Vertical = when (commentStyle) {
CommentStyle.AboveCandidates -> Alignment.Bottom
CommentStyle.BelowCandidates -> Alignment.Top
CommentStyle.NoComments -> Alignment.Bottom
}
val isDarkMode by context.isDarkMode.collectAsState()
val isHighContrastPreferred by context.isHighContrastPreferred.collectAsState()
val state = rememberLazyListState()
Expand All @@ -76,22 +56,15 @@ fun CandidateScrollBar() {
modifier = Modifier.fillMaxSize(),
state = state,
horizontalArrangement = Arrangement.spacedBy(0.dp),
verticalAlignment = candidateRowVerticalAlignment
verticalAlignment = Alignment.CenterVertically
) {
itemsIndexed(candidates) { index, candidate ->
items(candidates) {
CandidateView(
candidate = candidate,
candidate = it,
commentStyle = commentStyle,
isDarkMode = isDarkMode,
modifier = Modifier
.clickable(interactionSource = interactionSource, indication = null) {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
context.selectCandidate(index = index)
}
.padding(horizontal = if (candidate.type.isCantonese()) 6.dp else 10.dp)
.padding(vertical = if (candidate.type.isCantonese()) 0.dp else 4.dp)
.padding(top = candidateViewTopInset, bottom = candidateViewBottomInset)
selection = { context.selectCandidate(it) },
deletion = { context.forgetCandidate(it) }
)
}
}
Expand Down
86 changes: 84 additions & 2 deletions app/src/main/java/org/jyutping/jyutping/keyboard/CandidateView.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,104 @@
package org.jyutping.jyutping.keyboard

import android.view.HapticFeedbackConstants
import android.view.SoundEffectConstants
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
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.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.jyutping.jyutping.presets.PresetString

@Composable
fun CandidateView(candidate: Candidate, commentStyle: CommentStyle, isDarkMode: Boolean, modifier: Modifier) {
fun CandidateView(candidate: Candidate, commentStyle: CommentStyle, isDarkMode: Boolean, selection: () -> Unit, deletion: () -> Unit) {
val isCantonese: Boolean = candidate.type.isCantonese()
val textColor: Color = if (isDarkMode) Color.White else Color.Black
val view = LocalView.current
Box(
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
deletion()
},
onPress = {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS)
},
onTap = { selection() }
)
}
.padding(horizontal = if (isCantonese) 6.dp else 10.dp)
.fillMaxHeight(),
contentAlignment = Alignment.Center
) {
Color.Transparent
Box(
modifier = Modifier
.alpha(if (commentStyle.isNone()) 0f else 1f)
.fillMaxHeight(),
contentAlignment = if (commentStyle.isBelow()) Alignment.BottomCenter else Alignment.TopCenter
) {
Color.Transparent
Text(
text = if (isCantonese) candidate.romanization else PresetString.SPACE,
modifier = Modifier
.padding(vertical = 2.dp)
.height(20.dp),
color = textColor,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
Text(
text = candidate.text,
modifier = Modifier
.padding(bottom = if (commentStyle.isBelow()) 16.dp else 0.dp),
color = textColor,
fontSize = 20.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
}

@Composable
fun AltCandidateView(modifier: Modifier, candidate: Candidate, commentStyle: CommentStyle, isDarkMode: Boolean, selection: () -> Unit, deletion: () -> Unit) {
val isCantonese: Boolean = candidate.type.isCantonese()
val textColor: Color = if (isDarkMode) Color.White else Color.Black
val view = LocalView.current
Column(
modifier = modifier,
modifier = modifier
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
deletion()
},
onPress = {
view.playSoundEffect(SoundEffectConstants.CLICK)
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS)
},
onTap = { selection() }
)
},
verticalArrangement = Arrangement.spacedBy((-2).dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/org/jyutping/jyutping/keyboard/Engine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ object Engine {
return when (text.length) {
0 -> emptyList()
1 -> when (text) {
"a" -> db.pingMatch(text = text, input = text) + db.pingMatch(text = "aa", input = text, mark = text) + db.shortcutMatch(text)
"o", "m", "e" -> db.pingMatch(text = text, input = text) + db.shortcutMatch(text)
else -> db.shortcutMatch(text)
"a" -> db.pingMatch(text = text, input = text) + db.pingMatch(text = "aa", input = text, mark = text) + db.shortcutMatch(text = text, limit = 100)
"o", "m", "e" -> db.pingMatch(text = text, input = text) + db.shortcutMatch(text = text, limit = 100)
else -> db.shortcutMatch(text = text, limit = 100)
}
else -> {
if (asap) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.jyutping.jyutping.presets

@Suppress("ConstPropertyName")
object PresetConstant {
const val ToolBarHeight: Float = 60f
const val ToolBarHeight: Float = 56f
const val SpaceKeyLongPressHint: String = "← →"
const val keyboardPackageName: String = "org.jyutping.jyutping"
const val keyboardId: String = "org.jyutping.jyutping/.JyutpingInputMethodService"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,9 @@ class UserLexiconHelper(context: Context) : SQLiteOpenHelper(context, UserSettin
db?.execSQL(createTable)
}

fun handle(candidate: Candidate) {
val id: Int = (candidate.lexiconText + candidate.romanization).hashCode()
val frequency = find(id)
if (frequency != null) {
update(id = id, frequency = frequency)
} else {
val lexicon = UserLexicon.convert(candidate)
insert(lexicon)
}
}
fun process(candidates: List<Candidate>) {
val isNotAllCantonese = candidates.count { it.type.isNotCantonese() } > 0
if (isNotAllCantonese) return
val lexicon = UserLexicon.join(candidates)
val id = lexicon.id
val frequency = find(id)
Expand Down Expand Up @@ -66,6 +58,13 @@ class UserLexiconHelper(context: Context) : SQLiteOpenHelper(context, UserSettin
return null
}
}

fun remove(candidate: Candidate) {
if (candidate.type.isNotCantonese()) return
val id: Int = (candidate.lexiconText + candidate.romanization).hashCode()
val command: String = "DELETE FROM memory WHERE id = ${id};"
this.writableDatabase.execSQL(command)
}
fun deleteAll() {
val command: String = "DELETE FROM memory;"
this.writableDatabase.execSQL(command)
Expand Down

0 comments on commit c491f13

Please sign in to comment.