Skip to content

Commit

Permalink
add: toolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
ZTFtrue committed Feb 1, 2024
1 parent 8f170c1 commit af14e9c
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 90 deletions.
174 changes: 91 additions & 83 deletions app/src/main/java/com/ztftrue/music/ui/play/LyricsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -59,9 +60,9 @@ import androidx.media3.common.util.UnstableApi
import com.ztftrue.music.MainActivity
import com.ztftrue.music.MusicViewModel
import com.ztftrue.music.utils.ListStringCaption
import com.ztftrue.music.utils.textToolbar.CustomTextToolbar
import com.ztftrue.music.utils.LyricsType
import com.ztftrue.music.utils.Utils
import com.ztftrue.music.utils.textToolbar.CustomTextToolbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
Expand Down Expand Up @@ -278,110 +279,117 @@ fun LyricsView(
)
} else {
CompositionLocalProvider(
LocalTextToolbar provides CustomTextToolbar(LocalView.current)
LocalTextToolbar provides CustomTextToolbar(
LocalView.current,
musicViewModel.dictionaryAppList
)
) {
SelectionContainer {
LazyColumn(
state = listState,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
if (it.action == MotionEvent.ACTION_DOWN) {
val a = if (it.y > size.value.height / 2) {
it.y - fontSize * 3 - 60.dp.toPx(context)
} else {
it.y + fontSize * 3
SelectionContainer(
modifier = Modifier,
content = {
LazyColumn(
state = listState,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
if (it.action == MotionEvent.ACTION_DOWN) {
val a = if (it.y > size.value.height / 2) {
it.y - fontSize * 3 - 60.dp.toPx(context)
} else {
it.y + fontSize * 3
}
popupOffset = IntOffset(0, a.toInt())
}
popupOffset = IntOffset(0, a.toInt())
}
}
false
}
false
}
.motionEventSpy {
.motionEventSpy {

}
.onSizeChanged { sizeIt ->
size.value = sizeIt
}
.padding(start = 20.dp, end = 20.dp)
) {
items(musicViewModel.currentCaptionList.size) { listIndex ->
key(Unit) {
val tex = musicViewModel.currentCaptionList[listIndex].text
val annotatedString = buildAnnotatedString {
for ((index, text) in tex.withIndex()) {
val pattern = Regex("[,:;.\"]")
val tItem = text.replace(pattern, "")
pushStringAnnotation("word$tItem$index", tItem)
withStyle(
style = SpanStyle(
textDecoration = if (selectedTag == "$listIndex word$tItem$index") {
TextDecoration.Underline
} else {
TextDecoration.None
}
)
) {
append(text)
}
pop()
pushStringAnnotation("space", "")
append(" ")
pop()
}
}
ClickableText(
text = annotatedString,
style = TextStyle(
color = if (currentI == listIndex && musicViewModel.autoHighLight.value) {
Color.Blue
} else {
MaterialTheme.colorScheme.onBackground
},
fontSize = fontSize.sp,
textAlign = musicViewModel.textAlign.value,
lineHeight = (fontSize * 1.5).sp,
textIndent = if (musicViewModel.textAlign.value == TextAlign.Justify || musicViewModel.textAlign.value == TextAlign.Left) {
TextIndent(fontSize.sp * 2)
} else {
TextIndent.None
.onSizeChanged { sizeIt ->
size.value = sizeIt
}
.padding(start = 20.dp, end = 20.dp)
) {
items(musicViewModel.currentCaptionList.size) { listIndex ->
key(Unit) {
val tex = musicViewModel.currentCaptionList[listIndex].text
val annotatedString = buildAnnotatedString {
for ((index, text) in tex.withIndex()) {
val pattern = Regex("[,:;.\"]")
val tItem = text.replace(pattern, "")
pushStringAnnotation("word$tItem$index", tItem)
withStyle(
style = SpanStyle(
textDecoration = if (selectedTag == "$listIndex word$tItem$index") {
TextDecoration.Underline
} else {
TextDecoration.None
}
)
) {
append(text)
}
pop()
pushStringAnnotation("space", "")
append(" ")
pop()
}
),
modifier = Modifier
.fillMaxWidth()
.padding(2.dp)
) { offset ->
}
ClickableText(
text = annotatedString,
style = TextStyle(
color = if (currentI == listIndex && musicViewModel.autoHighLight.value) {
Color.Blue
} else {
MaterialTheme.colorScheme.onBackground
},
fontSize = fontSize.sp,
textAlign = musicViewModel.textAlign.value,
lineHeight = (fontSize * 1.5).sp,
textIndent = if (musicViewModel.textAlign.value == TextAlign.Justify || musicViewModel.textAlign.value == TextAlign.Left) {
TextIndent(fontSize.sp * 2)
} else {
TextIndent.None
}
),
modifier = Modifier
.fillMaxWidth()
.padding(2.dp)
) { offset ->

if (showMenu) {
showMenu = false
} else {
val annotations =
annotatedString.getStringAnnotations(offset, offset)
annotations.firstOrNull()?.let { itemAnnotations ->
if (itemAnnotations.tag.startsWith("word")) {
selectedTag = "$listIndex ${itemAnnotations.tag}"
word = itemAnnotations.item
showMenu = true
if (showMenu) {
showMenu = false
} else {
val annotations =
annotatedString.getStringAnnotations(offset, offset)
annotations.firstOrNull()?.let { itemAnnotations ->
if (itemAnnotations.tag.startsWith("word")) {
selectedTag = "$listIndex ${itemAnnotations.tag}"
word = itemAnnotations.item
showMenu = true
}
}
}
}

}
}
}

}
}
}
}
)
}
}


}


fun Dp.toPx(context: Context): Int {
val displayMetrics = context.resources.displayMetrics
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.value, displayMetrics)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package com.ztftrue.music.utils.textToolbar

import android.content.Intent
import android.view.ActionMode
import android.view.View
import androidx.annotation.DoNotInline
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus
import androidx.core.view.allViews
import com.ztftrue.music.sqlData.model.DictionaryApp

internal class CustomTextToolbar(private val view: View) : TextToolbar {

internal class CustomTextToolbar(
private val view: View,
private val customApp: List<DictionaryApp>,
) : TextToolbar {
private var actionMode: ActionMode? = null
private val textActionModeCallback: TextActionModeCallback = TextActionModeCallback()

Expand Down Expand Up @@ -40,6 +48,31 @@ internal class CustomTextToolbar(private val view: View) : TextToolbar {
textActionModeCallback.onCutRequested = onCutRequested
textActionModeCallback.onPasteRequested = onPasteRequested
textActionModeCallback.onSelectAllRequested = onSelectAllRequested
textActionModeCallback.customProcessTextApp = customApp
textActionModeCallback.onProcessAppItemClick = {
var min = 0
// var max: Int = view.getText().length()
// if (mTextView.isFocused()) {
// val selStart: Int = mTextView.getSelectionStart()
// val selEnd: Int = mTextView.getSelectionEnd()
// min = Math.max(0, Math.min(selStart, selEnd))
// max = Math.max(0, Math.max(selStart, selEnd))
// }
// // Perform your definition lookup with the selected text
// // Perform your definition lookup with the selected text
// val selectedText: CharSequence = mTextView.getText().subSequence(min, max)
val intent = Intent()
intent.setAction(Intent.ACTION_PROCESS_TEXT)
intent.setClassName(
it.packageName,
it.name
)
intent.putExtra(
Intent.EXTRA_PROCESS_TEXT,
actionMode?.title
)
view.context.startActivity(intent)
}
if (actionMode == null) {
status = TextToolbarStatus.Shown
actionMode =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal class FloatingTextActionModeCallback(
private val callback: TextActionModeCallback
) : ActionMode.Callback2() {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {

return callback.onActionItemClicked(mode, item)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import android.view.Menu
import android.view.MenuItem
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.geometry.Rect
import com.ztftrue.music.sqlData.model.DictionaryApp
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.ui.platform.compositionContext

internal class TextActionModeCallback(
var rect: Rect = Rect.Zero,
Expand All @@ -13,6 +16,8 @@ internal class TextActionModeCallback(
var onPasteRequested: (() -> Unit)? = null,
var onCutRequested: (() -> Unit)? = null,
var onSelectAllRequested: (() -> Unit)? = null,
var customProcessTextApp: List<DictionaryApp>? = null,
var onProcessAppItemClick: ((DictionaryApp) -> Unit)? = null
) {
fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
requireNotNull(menu)
Expand All @@ -21,6 +26,9 @@ internal class TextActionModeCallback(
onCopyRequested?.let {
addMenuItem(menu, MenuItemOption.Copy)
}
customProcessTextApp?.forEachIndexed() { index, it ->
addMenuItemDictionaryApp(menu, it, index)
}
onPasteRequested?.let {
addMenuItem(menu, MenuItemOption.Paste)
}
Expand All @@ -42,12 +50,32 @@ internal class TextActionModeCallback(
}

fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item!!.itemId) {
MenuItemOption.Copy.id -> onCopyRequested?.invoke()
MenuItemOption.Paste.id -> onPasteRequested?.invoke()
MenuItemOption.Cut.id -> onCutRequested?.invoke()
MenuItemOption.SelectAll.id -> onSelectAllRequested?.invoke()
else -> return false
if (item != null) {
if (item.groupId == 0) {
when (item.itemId) {
MenuItemOption.Copy.id -> onCopyRequested?.invoke()
MenuItemOption.Paste.id -> onPasteRequested?.invoke()
MenuItemOption.Cut.id -> onCutRequested?.invoke()
MenuItemOption.SelectAll.id -> onSelectAllRequested?.invoke()
}
} else if (item.groupId == 1) {
val app = customProcessTextApp?.get(item.order)
if (app != null) {

// var min = 0
// var max: Int = view.getText().length()
// if (mTextView.isFocused()) {
// val selStart: Int = mTextView.getSelectionStart()
// val selEnd: Int = mTextView.getSelectionEnd()
// min = Math.max(0, Math.min(selStart, selEnd))
// max = Math.max(0, Math.max(selStart, selEnd))
// }
// // Perform your definition lookup with the selected text
// // Perform your definition lookup with the selected text
// val selectedText: CharSequence = mTextView.getText().subSequence(min, max)
onProcessAppItemClick?.invoke(app)
}
}
}
mode?.finish()
return true
Expand All @@ -63,13 +91,21 @@ internal class TextActionModeCallback(
addOrRemoveMenuItem(menu, MenuItemOption.Paste, onPasteRequested)
addOrRemoveMenuItem(menu, MenuItemOption.Cut, onCutRequested)
addOrRemoveMenuItem(menu, MenuItemOption.SelectAll, onSelectAllRequested)
customProcessTextApp?.forEachIndexed() { index, it ->
addOrRemoveMenuAppItem(menu, it, index, onProcessAppItemClick)
}
}

internal fun addMenuItem(menu: Menu, item: MenuItemOption) {
menu.add(0, item.id, item.order, item.titleResource)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}

internal fun addMenuItemDictionaryApp(menu: Menu, item: DictionaryApp, index: Int) {
menu.add(1, index + 10, index, item.label)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}

private fun addOrRemoveMenuItem(
menu: Menu,
item: MenuItemOption,
Expand All @@ -80,8 +116,26 @@ internal class TextActionModeCallback(
callback == null && menu.findItem(item.id) != null -> menu.removeItem(item.id)
}
}

private fun addOrRemoveMenuAppItem(
menu: Menu,
item: DictionaryApp,
index: Int,
callback: ((d: DictionaryApp) -> Unit)?
) {
// TODO magic number, because this default max number is 4.
when {
callback != null && menu.findItem(index + 10) == null -> addMenuItemDictionaryApp(
menu,
item,
index
)
callback == null && menu.findItem(index + 10) != null -> menu.removeItem(index + 10)
}
}
}


internal enum class MenuItemOption(val id: Int) {
Copy(0),
Paste(1),
Expand Down

0 comments on commit af14e9c

Please sign in to comment.