mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-21 09:40:37 +02:00
Paste text in calculator
This commit is contained in:
parent
3bc9891b81
commit
684d7f2d9a
@ -79,7 +79,8 @@ private fun CalculatorScreen(
|
|||||||
text = uiState.input,
|
text = uiState.input,
|
||||||
selection = TextRange(uiState.selection.first, uiState.selection.last)
|
selection = TextRange(uiState.selection.first, uiState.selection.last)
|
||||||
),
|
),
|
||||||
onCursorChange = onCursorChange
|
onCursorChange = onCursorChange,
|
||||||
|
pasteCallback = addSymbol
|
||||||
)
|
)
|
||||||
AnimatedVisibility(visible = uiState.output.isNotEmpty()) {
|
AnimatedVisibility(visible = uiState.output.isNotEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -121,6 +121,8 @@ internal class CalculatorViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onCursorChange(selection: IntRange) {
|
fun onCursorChange(selection: IntRange) {
|
||||||
|
// When we paste, selection is set to the length of the pasted text (start and end)
|
||||||
|
if (selection.first > _input.value.length) return
|
||||||
_selection.update { selection }
|
_selection.update { selection }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2023 Elshan Agaev
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sadellie.unitto.feature.calculator.components
|
||||||
|
|
||||||
|
import android.view.ActionMode
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
|
||||||
|
@RequiresApi(23)
|
||||||
|
internal class FloatingTextActionModeCallback(
|
||||||
|
private val callback: UnittoActionModeCallback
|
||||||
|
) : ActionMode.Callback2() {
|
||||||
|
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
|
return callback.onActionItemClicked(mode, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
return callback.onCreateActionMode(mode, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
return callback.onPrepareActionMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
|
callback.onDestroyActionMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGetContentRect(
|
||||||
|
mode: ActionMode?,
|
||||||
|
view: View?,
|
||||||
|
outRect: android.graphics.Rect?
|
||||||
|
) {
|
||||||
|
val rect = callback.rect
|
||||||
|
outRect?.set(
|
||||||
|
rect.left.toInt(),
|
||||||
|
rect.top.toInt(),
|
||||||
|
rect.right.toInt(),
|
||||||
|
rect.bottom.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,10 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
import androidx.compose.ui.platform.LocalTextInputService
|
import androidx.compose.ui.platform.LocalTextInputService
|
||||||
|
import androidx.compose.ui.platform.LocalTextToolbar
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayLarge
|
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayLarge
|
||||||
@ -32,16 +35,24 @@ import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayLarge
|
|||||||
internal fun InputTextField(
|
internal fun InputTextField(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
value: TextFieldValue,
|
value: TextFieldValue,
|
||||||
onCursorChange: (IntRange) -> Unit
|
onCursorChange: (IntRange) -> Unit,
|
||||||
|
pasteCallback: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val clipboardManager = LocalClipboardManager.current
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
// FIXME Can't paste if this is null
|
LocalTextInputService provides null,
|
||||||
LocalTextInputService provides null
|
LocalTextToolbar provides UnittoTextToolbar(
|
||||||
|
view = LocalView.current,
|
||||||
|
pasteCallback = { pasteCallback(clipboardManager.getText()?.text ?: "") }
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
singleLine = true,
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = { onCursorChange(it.selection.start..it.selection.end) },
|
onValueChange = {
|
||||||
|
onCursorChange(it.selection.start..it.selection.end)
|
||||||
|
},
|
||||||
textStyle = NumbersTextStyleDisplayLarge.copy(
|
textStyle = NumbersTextStyleDisplayLarge.copy(
|
||||||
textAlign = TextAlign.End,
|
textAlign = TextAlign.End,
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2023 Elshan Agaev
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sadellie.unitto.feature.calculator.components
|
||||||
|
|
||||||
|
import android.view.ActionMode
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
|
||||||
|
private const val MENU_ITEM_COPY = 0
|
||||||
|
private const val MENU_ITEM_PASTE = 1
|
||||||
|
private const val MENU_ITEM_CUT = 2
|
||||||
|
private const val MENU_ITEM_SELECT_ALL = 3
|
||||||
|
|
||||||
|
internal class UnittoActionModeCallback(
|
||||||
|
var rect: Rect = Rect.Zero,
|
||||||
|
var onCopyRequested: (() -> Unit)? = null,
|
||||||
|
var onPasteRequested: (() -> Unit)? = null,
|
||||||
|
var onCutRequested: (() -> Unit)? = null,
|
||||||
|
var onSelectAllRequested: (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
requireNotNull(menu)
|
||||||
|
requireNotNull(mode)
|
||||||
|
|
||||||
|
onCopyRequested?.let {
|
||||||
|
menu.add(0, MENU_ITEM_COPY, 0, android.R.string.copy)
|
||||||
|
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPasteRequested?.let {
|
||||||
|
menu.add(0, MENU_ITEM_PASTE, 1, android.R.string.paste)
|
||||||
|
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
||||||
|
}
|
||||||
|
|
||||||
|
onCutRequested?.let {
|
||||||
|
menu.add(0, MENU_ITEM_CUT, 2, android.R.string.cut)
|
||||||
|
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectAllRequested?.let {
|
||||||
|
menu.add(0, MENU_ITEM_SELECT_ALL, 3, android.R.string.selectAll)
|
||||||
|
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrepareActionMode(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
|
when (item!!.itemId) {
|
||||||
|
MENU_ITEM_COPY -> onCopyRequested?.invoke()
|
||||||
|
MENU_ITEM_PASTE -> onPasteRequested?.invoke()
|
||||||
|
MENU_ITEM_CUT -> onCutRequested?.invoke()
|
||||||
|
MENU_ITEM_SELECT_ALL -> onSelectAllRequested?.invoke()
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
mode?.finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDestroyActionMode() {}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2023 Elshan Agaev
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sadellie.unitto.feature.calculator.components
|
||||||
|
|
||||||
|
import android.view.ActionMode
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
|
||||||
|
internal class UnittoPrimaryTextActionModeCallback(
|
||||||
|
private val callback: UnittoActionModeCallback
|
||||||
|
) : ActionMode.Callback {
|
||||||
|
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
|
return callback.onActionItemClicked(mode, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
return callback.onCreateActionMode(mode, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
return callback.onPrepareActionMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
|
callback.onDestroyActionMode()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2023 Elshan Agaev
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sadellie.unitto.feature.calculator.components
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.ActionMode
|
||||||
|
import android.view.View
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
import androidx.compose.ui.platform.TextToolbar
|
||||||
|
import androidx.compose.ui.platform.TextToolbarStatus
|
||||||
|
|
||||||
|
internal class UnittoTextToolbar(
|
||||||
|
private val view: View,
|
||||||
|
private val pasteCallback: () -> Unit
|
||||||
|
) : TextToolbar {
|
||||||
|
|
||||||
|
private var actionMode: ActionMode? = null
|
||||||
|
private val textActionModeCallback: UnittoActionModeCallback = UnittoActionModeCallback()
|
||||||
|
override var status: TextToolbarStatus = TextToolbarStatus.Hidden
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun showMenu(
|
||||||
|
rect: Rect,
|
||||||
|
onCopyRequested: (() -> Unit)?,
|
||||||
|
onPasteRequested: (() -> Unit)?,
|
||||||
|
onCutRequested: (() -> Unit)?,
|
||||||
|
onSelectAllRequested: (() -> Unit)?
|
||||||
|
) {
|
||||||
|
textActionModeCallback.rect = rect
|
||||||
|
textActionModeCallback.onCopyRequested = onCopyRequested
|
||||||
|
textActionModeCallback.onCutRequested = onCutRequested
|
||||||
|
textActionModeCallback.onPasteRequested = { pasteCallback(); onPasteRequested?.invoke() }
|
||||||
|
textActionModeCallback.onSelectAllRequested = onSelectAllRequested
|
||||||
|
if (actionMode == null) {
|
||||||
|
status = TextToolbarStatus.Shown
|
||||||
|
actionMode = startActionMode(view, textActionModeCallback)
|
||||||
|
} else {
|
||||||
|
actionMode?.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
status = TextToolbarStatus.Hidden
|
||||||
|
actionMode?.finish()
|
||||||
|
actionMode = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startActionMode(
|
||||||
|
view: View,
|
||||||
|
textActionModeCallback: UnittoActionModeCallback
|
||||||
|
): ActionMode {
|
||||||
|
return if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
view.startActionMode(
|
||||||
|
FloatingTextActionModeCallback(textActionModeCallback),
|
||||||
|
ActionMode.TYPE_FLOATING
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Old devices use toolbar instead of a floating menu
|
||||||
|
view.startActionMode(
|
||||||
|
UnittoPrimaryTextActionModeCallback(textActionModeCallback)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user