From 3b0ef233e7f482b4541da9069400726d19890f2b Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 21 Jun 2024 18:09:46 +0200 Subject: [PATCH] feat: support for duration inputs in submit segment dialog --- app/build.gradle.kts | 1 + .../ui/dialogs/SubmitSegmentDialog.kt | 8 ++-- .../com/github/libretube/util/TextUtils.kt | 41 ++++++++++++++++++- .../main/res/layout/dialog_submit_segment.xml | 3 +- .../com/github/libretube/TextParserTest.kt | 16 ++++++++ gradle/libs.versions.toml | 4 ++ 6 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 app/src/test/java/com/github/libretube/TextParserTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4233e49bf..7a4cefb83 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -126,6 +126,7 @@ dependencies { implementation(libs.kotlinx.serialization) implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.retrofit) + testImplementation(libs.testng) /* Cronet and Coil */ coreLibraryDesugaring(libs.desugaring) diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt index 786f27379..43b2e28e8 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt @@ -18,6 +18,7 @@ import com.github.libretube.extensions.TAG import com.github.libretube.extensions.toastFromMainDispatcher import com.github.libretube.helpers.PreferenceHelper import com.github.libretube.util.TextUtils +import com.github.libretube.util.TextUtils.parseDurationString import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -52,7 +53,7 @@ class SubmitSegmentDialog : DialogFragment() { lifecycleScope.launch { voteForSegment() } } - binding.startTime.setText((currentPosition.toFloat() / 1000).toString()) + binding.startTime.setText(DateUtils.formatElapsedTime(((currentPosition.toFloat() / 1000).toLong()))) binding.segmentCategory.items = resources.getStringArray(R.array.sponsorBlockSegmentNames).toList() @@ -72,8 +73,9 @@ class SubmitSegmentDialog : DialogFragment() { requireDialog().hide() - val startTime = binding.startTime.text.toString().toFloatOrNull() - var endTime = binding.endTime.text.toString().toFloatOrNull() + val startTime = binding.startTime.text.toString().parseDurationString() + var endTime = binding.endTime.text.toString().parseDurationString() + if (endTime == null || startTime == null || startTime > endTime) { context.toastFromMainDispatcher(R.string.sb_invalid_segment) return diff --git a/app/src/main/java/com/github/libretube/util/TextUtils.kt b/app/src/main/java/com/github/libretube/util/TextUtils.kt index ff84891f9..8ba8d0b2a 100644 --- a/app/src/main/java/com/github/libretube/util/TextUtils.kt +++ b/app/src/main/java/com/github/libretube/util/TextUtils.kt @@ -7,6 +7,7 @@ import android.os.Build import android.text.format.DateUtils import com.github.libretube.BuildConfig import com.github.libretube.R +import com.google.common.math.IntMath.pow import kotlinx.datetime.toJavaLocalDate import java.time.Instant import java.time.LocalDateTime @@ -49,8 +50,44 @@ object TextUtils { * Get time in seconds from a YouTube video link. * @return Time in seconds */ - fun String.toTimeInSeconds(): Long? { - return toLongOrNull() ?: Duration.parseOrNull(this)?.inWholeSeconds + fun String.toTimeInSeconds(): Long? = parseTimeString(this)?.toLong() + + fun String.parseDurationString(): Float? = parseTimeString(this) + + private fun parseTimeString(timeString: String): Float? { + if (timeString.all { it.isDigit() }) return timeString.toLongOrNull()?.toFloat() + + if (timeString.all { it.isDigit() || ",.:".contains(it) }) { + var secondsTotal = 0 + var secondsScoped = 0 + + var milliseconds = 0 + var inMillis = false + + for (char in timeString) { + if (inMillis) { + if (!char.isDigit()) break + + milliseconds *= 10 + milliseconds += char.digitToInt() + } else if (char.isDigit()) { + secondsScoped *= 10 + secondsScoped += char.digitToInt() + } else if (char == ':') { + secondsTotal += secondsScoped * 60 + secondsScoped = 0 + } else if (",.".contains(char)) { + secondsTotal += secondsScoped + secondsScoped = 0 + inMillis = true + } + } + + val millisDecimal = milliseconds.toFloat() / pow(10, milliseconds.toString().length) + return secondsTotal.toFloat() + millisDecimal + } + + return Duration.parseOrNull(timeString)?.inWholeMilliseconds?.toFloat()?.div(1000) } /** diff --git a/app/src/main/res/layout/dialog_submit_segment.xml b/app/src/main/res/layout/dialog_submit_segment.xml index 8e2474d75..01d271db8 100644 --- a/app/src/main/res/layout/dialog_submit_segment.xml +++ b/app/src/main/res/layout/dialog_submit_segment.xml @@ -35,7 +35,8 @@ android:id="@+id/start_time" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="numberDecimal" /> + android:digits="0123456789.:" + android:inputType="number" />