fixed some bugs

This commit is contained in:
2026-08-24 14:25:31 +08:00
parent 8d4a81b4f5
commit 28674def97
5 changed files with 148 additions and 43 deletions

View File

@@ -28,6 +28,7 @@ class OralTrainerPlayerView @JvmOverloads constructor(
private var longPressStartY = 0f private var longPressStartY = 0f
private var longPressActive = false private var longPressActive = false
private var speedBeforeLongPress: Float? = null private var speedBeforeLongPress: Float? = null
private var verticalSwipeListener: ((isSwipeUp: Boolean) -> Unit)? = null
private val longPressSpeedRunnable = Runnable { private val longPressSpeedRunnable = Runnable {
val activeController = controller ?: return@Runnable val activeController = controller ?: return@Runnable
@@ -70,6 +71,11 @@ class OralTrainerPlayerView @JvmOverloads constructor(
val dy = e2.y - start.y val dy = e2.y - start.y
val minDistancePx = gestureControls.minSwipeDistanceDp * density val minDistancePx = gestureControls.minSwipeDistanceDp * density
val minVelocityPx = gestureControls.minSwipeVelocityDpPerSecond * density val minVelocityPx = gestureControls.minSwipeVelocityDpPerSecond * density
if (abs(dy) > minDistancePx && abs(dy) > abs(dx) && abs(velocityY) >= minVelocityPx) {
val isSwipeUp = dy < 0
verticalSwipeListener?.invoke(isSwipeUp)
return true
}
if (abs(dx) < abs(dy) || abs(dx) < minDistancePx || abs(velocityX) < minVelocityPx) { if (abs(dx) < abs(dy) || abs(dx) < minDistancePx || abs(velocityX) < minVelocityPx) {
return false return false
} }
@@ -112,6 +118,10 @@ class OralTrainerPlayerView @JvmOverloads constructor(
gestureControls = config gestureControls = config
} }
fun setVerticalSwipeListener(listener: ((isSwipeUp: Boolean) -> Unit)?) {
verticalSwipeListener = listener
}
override fun onTouchEvent(event: MotionEvent): Boolean { override fun onTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event) return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
} }

View File

@@ -19,7 +19,7 @@ android {
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 35
versionCode = 1 versionCode = 1
versionName = "0.1.0" versionName = "0.1.1"
} }
compileOptions { compileOptions {

View File

@@ -2,8 +2,11 @@ package cn.learningpad.oraltrainer.sample
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.BroadcastReceiver
import android.content.Context
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
@@ -17,11 +20,13 @@ import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.TranslateAnimation
import android.widget.Button import android.widget.Button
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.HorizontalScrollView
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.HorizontalScrollView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Switch import android.widget.Switch
@@ -75,6 +80,15 @@ class MainActivity : Activity() {
private var catalogStatusTextValue = "正在同步" private var catalogStatusTextValue = "正在同步"
private var activeModule = Module.TRAIN private var activeModule = Module.TRAIN
private var continuousPlaybackEnabled = false private var continuousPlaybackEnabled = false
private var landscapeSubtitleVisible = true
private val screenActionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == Intent.ACTION_SCREEN_OFF) {
controller.pause()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -104,6 +118,11 @@ class MainActivity : Activity() {
setContentView(createContentView()) setContentView(createContentView())
loadCatalog() loadCatalog()
refreshCurrentUi() refreshCurrentUi()
registerReceiver(
screenActionReceiver,
IntentFilter(Intent.ACTION_SCREEN_OFF),
)
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
@@ -132,6 +151,33 @@ class MainActivity : Activity() {
} }
} }
override fun onPause() {
super.onPause()
controller.pause()
}
override fun onResume() {
super.onResume()
registerReceiver(
screenActionReceiver,
IntentFilter(Intent.ACTION_SCREEN_OFF),
)
}
override fun onStop() {
runCatching { unregisterReceiver(screenActionReceiver) }
super.onStop()
}
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
} else {
moveTaskToBack(true)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode != PICK_VIDEO_REQUEST || resultCode != RESULT_OK) { if (requestCode != PICK_VIDEO_REQUEST || resultCode != RESULT_OK) {
@@ -277,8 +323,7 @@ class MainActivity : Activity() {
setBackgroundColor(Color.BLACK) setBackgroundColor(Color.BLACK)
addView(createPlayerView()) addView(createPlayerView())
addView(createPlayerOverlay()) addView(createPlayerOverlay())
addView( val subtitleContainer = LinearLayout(this@MainActivity).apply {
LinearLayout(this@MainActivity).apply {
orientation = LinearLayout.VERTICAL orientation = LinearLayout.VERTICAL
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -291,12 +336,69 @@ class MainActivity : Activity() {
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
) )
}) })
addView(createRotationButtonRow())
} }
) addView(subtitleContainer)
applyLandscapeSubtitleState(subtitleContainer, animate = false)
installLandscapeSwipeGesture(subtitleContainer)
} }
} }
private fun installLandscapeSwipeGesture(subtitleContainer: View) {
playerView.setVerticalSwipeListener { isSwipeUp ->
if (isSwipeUp == landscapeSubtitleVisible) {
return@setVerticalSwipeListener
}
landscapeSubtitleVisible = isSwipeUp
applyLandscapeSubtitleState(subtitleContainer, animate = true)
}
}
private fun applyLandscapeSubtitleState(container: View, animate: Boolean) {
if (!animate || container.visibility == View.GONE) {
container.clearAnimation()
if (landscapeSubtitleVisible) {
container.visibility = View.VISIBLE
} else {
container.visibility = View.GONE
}
return
}
if (landscapeSubtitleVisible) {
container.visibility = View.VISIBLE
container.post {
if (landscapeSubtitleVisible && container.visibility == View.VISIBLE) {
startSlideAnimation(container, fromYDelta = 1f, toYDelta = 0f) {
container.visibility = View.VISIBLE
}
}
}
} else {
startSlideAnimation(container, fromYDelta = 0f, toYDelta = 1f) {
container.visibility = View.GONE
}
}
}
private fun startSlideAnimation(
view: View,
fromYDelta: Float,
toYDelta: Float,
onEnd: () -> Unit,
) {
val animation = TranslateAnimation(0f, 0f, view.height * fromYDelta, view.height * toYDelta).apply {
duration = 220L
fillAfter = true
setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) = Unit
override fun onAnimationRepeat(animation: Animation?) = Unit
override fun onAnimationEnd(animation: Animation?) {
view.post(onEnd)
}
})
}
view.startAnimation(animation)
}
private fun createLandscapeSentencePanel(): View { private fun createLandscapeSentencePanel(): View {
return createSentenceContent(translucent = true).apply { return createSentenceContent(translucent = true).apply {
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
@@ -391,36 +493,19 @@ class MainActivity : Activity() {
return overlay return overlay
} }
private fun createRotationButtonRow(): View {
return LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.END
setPadding(0, 0, 12.dp, 12.dp)
addView(createRotationButton())
}
}
private fun createRotationButton(): ImageButton { private fun createRotationButton(): ImageButton {
val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
return ImageButton(this).apply { return ImageButton(this).apply {
setImageResource(R.drawable.ic_screen_rotation) setImageResource(R.drawable.ic_screen_rotation)
imageTintList = ColorStateList.valueOf(Color.WHITE) imageTintList = ColorStateList.valueOf(Color.WHITE)
background = rounded(Color.argb(178, 9, 12, 16), 22.dp.toFloat()) background = rounded(Color.argb(178, 9, 12, 16), 22.dp.toFloat())
scaleType = ImageView.ScaleType.CENTER_INSIDE scaleType = ImageView.ScaleType.CENTER_INSIDE
setPadding(10.dp, 10.dp, 10.dp, 10.dp) setPadding(10.dp, 10.dp, 10.dp, 10.dp)
contentDescription = if (isLandscape) "竖屏" else "横屏" contentDescription = "横屏"
layoutParams = LinearLayout.LayoutParams(44.dp, 44.dp) layoutParams = LinearLayout.LayoutParams(44.dp, 44.dp)
setOnClickListener { toggleOrientation() } setOnClickListener {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
} }
} }
private fun toggleOrientation() {
val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
requestedOrientation = if (isLandscape) {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
} else {
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
} }
private fun createSentenceSection(): View { private fun createSentenceSection(): View {

View File

@@ -1,9 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="48"
android:viewportHeight="24.0"> android:viewportHeight="48">
<path <path
android:fillColor="#FFFFFFFF" android:strokeColor="@android:color/white"
android:pathData="M16.48,2.52c3,2.02 5.02,5.27 5.02,9.48 0,1.77 -0.38,3.45 -1.06,4.97L10.02,2.94C11.39,2.51 12.86,2.28 14.4,2.28c0.74,0 1.47,0.08 2.08,0.24zM10.02,21.06L1.56,7.43C0.56,8.82 0,10.36 0,12c0,4.97 4.03,9 9,9h0.51C9.73,21.06 9.87,21.06 10.02,21.06zM9,22.06C3.96,22.06 -0.03,18.08 -0.03,13.04c0,-1.6 0.39,-3.11 1.07,-4.44l8.57,13.12C9.63,21.72 9.6,21.88 9.6,22.06 9.6,22.06 9.6,22.06 9,22.06zM20.93,5.44c0.68,1.33 1.07,2.84 1.07,4.44 0,5.04 -3.99,9.02 -9.03,9.02 -0.2,0 -0.4,-0.01 -0.6,-0.02l8.56,-13.44L20.93,5.44z"/> android:strokeWidth="3.2"
android:pathData="M15,15h10v20h-10z"/>
<path
android:strokeColor="@android:color/white"
android:strokeWidth="3.2"
android:strokeLineCap="round"
android:pathData="M25,11a12,12 0 0 1 11,7.3"/>
<path
android:fillColor="@android:color/white"
android:pathData="M40.8,14.6L37.2,20.4L34.1,13.8Z"/>
</vector> </vector>

View File

@@ -2,7 +2,8 @@
<style name="AppTheme" parent="android:style/Theme.Material.NoActionBar"> <style name="AppTheme" parent="android:style/Theme.Material.NoActionBar">
<item name="android:windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">false</item> <item name="android:windowFullscreen">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:fontFamily">sans</item> <item name="android:fontFamily">sans</item>
<item name="android:colorAccent">#2563EB</item> <item name="android:colorAccent">#2563EB</item>
</style> </style>