Copy from output and history

This commit is contained in:
Sad Ellie 2023-02-26 16:55:56 +04:00
parent a1333f5746
commit 65e6f7545e
4 changed files with 91 additions and 66 deletions

View File

@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.MoreVert
@ -44,6 +45,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -53,7 +55,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
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 androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -69,6 +75,7 @@ import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard
import com.sadellie.unitto.feature.calculator.components.DragDownView import com.sadellie.unitto.feature.calculator.components.DragDownView
import com.sadellie.unitto.feature.calculator.components.HistoryList import com.sadellie.unitto.feature.calculator.components.HistoryList
import com.sadellie.unitto.feature.calculator.components.InputTextField import com.sadellie.unitto.feature.calculator.components.InputTextField
import com.sadellie.unitto.feature.calculator.components.UnittoTextToolbar
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -81,20 +88,37 @@ internal fun CalculatorRoute(
navigateToSettings: () -> Unit, navigateToSettings: () -> Unit,
viewModel: CalculatorViewModel = hiltViewModel() viewModel: CalculatorViewModel = hiltViewModel()
) { ) {
val clipboardManager = LocalClipboardManager.current
val uiState = viewModel.uiState.collectAsStateWithLifecycle() val uiState = viewModel.uiState.collectAsStateWithLifecycle()
CalculatorScreen( fun copyToClipboard() {
uiState = uiState.value, val clipboardText = clipboardManager.getText() ?: return
navigateToMenu = navigateToMenu, // This method is called immediately after copying formatted text, we replace it with the
navigateToSettings = navigateToSettings, // the unformatted version.
addSymbol = viewModel::addSymbol, clipboardManager.setText(
clearSymbols = viewModel::clearSymbols, AnnotatedString(Formatter.removeFormat(clipboardText.text))
deleteSymbol = viewModel::deleteSymbol, )
onCursorChange = viewModel::onCursorChange, }
toggleAngleMode = viewModel::toggleCalculatorMode,
evaluate = viewModel::evaluate, CompositionLocalProvider(
clearHistory = viewModel::clearHistory LocalTextToolbar provides UnittoTextToolbar(
) view = LocalView.current,
copyCallback = ::copyToClipboard
)
) {
CalculatorScreen(
uiState = uiState.value,
navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings,
addSymbol = viewModel::addSymbol,
clearSymbols = viewModel::clearSymbols,
deleteSymbol = viewModel::deleteSymbol,
onCursorChange = viewModel::onCursorChange,
toggleAngleMode = viewModel::toggleCalculatorMode,
evaluate = viewModel::evaluate,
clearHistory = viewModel::clearHistory
)
}
} }
@Composable @Composable
@ -209,16 +233,18 @@ private fun CalculatorScreen(
pasteCallback = addSymbol, pasteCallback = addSymbol,
cutCallback = deleteSymbol cutCallback = deleteSymbol
) )
Text( SelectionContainer {
modifier = Modifier Text(
.fillMaxWidth() modifier = Modifier
.padding(horizontal = 8.dp), .fillMaxWidth()
text = Formatter.format(uiState.output), .padding(horizontal = 8.dp),
textAlign = TextAlign.End, text = Formatter.format(uiState.output),
softWrap = false, textAlign = TextAlign.End,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f), softWrap = false,
style = NumbersTextStyleDisplayMedium, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
) style = NumbersTextStyleDisplayMedium,
)
}
// Handle // Handle
Box( Box(
Modifier Modifier

View File

@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.History import androidx.compose.material.icons.filled.History
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -115,36 +116,38 @@ private fun HistoryListItem(
historyItem: HistoryItem, historyItem: HistoryItem,
onTextClick: (String) -> Unit onTextClick: (String) -> Unit
) { ) {
Column(modifier = modifier) { SelectionContainer {
Box( Column(modifier = modifier) {
Modifier.clickable { onTextClick(historyItem.expression) } Box(
) { Modifier.clickable { onTextClick(historyItem.expression) }
Text( ) {
text = Formatter.format(historyItem.expression), Text(
maxLines = 1, text = Formatter.format(historyItem.expression),
modifier = Modifier maxLines = 1,
.fillMaxWidth() modifier = Modifier
.padding(horizontal = 8.dp) .fillMaxWidth()
.horizontalScroll(rememberScrollState(), reverseScrolling = true), .padding(horizontal = 8.dp)
style = NumbersTextStyleDisplayMedium, .horizontalScroll(rememberScrollState(), reverseScrolling = true),
color = MaterialTheme.colorScheme.onSurfaceVariant, style = NumbersTextStyleDisplayMedium,
textAlign = TextAlign.End color = MaterialTheme.colorScheme.onSurfaceVariant,
) textAlign = TextAlign.End
} )
Box( }
Modifier.clickable { onTextClick(historyItem.result) } Box(
) { Modifier.clickable { onTextClick(historyItem.result) }
Text( ) {
text = Formatter.format(historyItem.result), Text(
maxLines = 1, text = Formatter.format(historyItem.result),
modifier = Modifier maxLines = 1,
.fillMaxWidth() modifier = Modifier
.padding(horizontal = 8.dp) .fillMaxWidth()
.horizontalScroll(rememberScrollState(), reverseScrolling = true), .padding(horizontal = 8.dp)
style = NumbersTextStyleDisplayMedium, .horizontalScroll(rememberScrollState(), reverseScrolling = true),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f), style = NumbersTextStyleDisplayMedium,
textAlign = TextAlign.End color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f),
) textAlign = TextAlign.End
)
}
} }
} }
} }

View File

@ -30,7 +30,6 @@ 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.LocalTextToolbar
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.AnnotatedString
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.base.Separator import com.sadellie.unitto.core.base.Separator
@ -57,21 +56,16 @@ internal fun InputTextField(
} }
fun copyToClipboard() = clipboardManager.setText( fun copyToClipboard() = clipboardManager.setText(
AnnotatedString( formattedInput.annotatedString.subSequence(formattedInput.selection)
Formatter.removeFormat(formattedInput.text)
)
) )
CompositionLocalProvider( CompositionLocalProvider(
LocalTextInputService provides null, LocalTextInputService provides null,
LocalTextToolbar provides UnittoTextToolbar( LocalTextToolbar provides UnittoTextToolbar(
view = LocalView.current, view = LocalView.current,
copyCallback = ::copyToClipboard,
pasteCallback = { pasteCallback(clipboardManager.getText()?.text ?: "") }, pasteCallback = { pasteCallback(clipboardManager.getText()?.text ?: "") },
cutCallback = { cutCallback = { copyToClipboard(); cutCallback() }
copyToClipboard()
cutCallback()
},
copyCallback = ::copyToClipboard
) )
) { ) {
BasicTextField( BasicTextField(

View File

@ -27,9 +27,9 @@ import androidx.compose.ui.platform.TextToolbarStatus
internal class UnittoTextToolbar( internal class UnittoTextToolbar(
private val view: View, private val view: View,
private val pasteCallback: () -> Unit, private val copyCallback: () -> Unit,
private val cutCallback: () -> Unit, private val pasteCallback: (() -> Unit)? = null,
private val copyCallback: () -> Unit private val cutCallback: (() -> Unit)? = null
) : TextToolbar { ) : TextToolbar {
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
@ -45,8 +45,10 @@ internal class UnittoTextToolbar(
onSelectAllRequested: (() -> Unit)? onSelectAllRequested: (() -> Unit)?
) { ) {
textActionModeCallback.rect = rect textActionModeCallback.rect = rect
textActionModeCallback.onCopyRequested = copyCallback textActionModeCallback.onCopyRequested = { onCopyRequested?.invoke(); copyCallback.invoke() }
textActionModeCallback.onCutRequested = cutCallback textActionModeCallback.onCutRequested = cutCallback?.let {
{ it.invoke(); onCutRequested?.invoke() }
}
textActionModeCallback.onPasteRequested = pasteCallback textActionModeCallback.onPasteRequested = pasteCallback
textActionModeCallback.onSelectAllRequested = onSelectAllRequested textActionModeCallback.onSelectAllRequested = onSelectAllRequested
if (actionMode == null) { if (actionMode == null) {