Skip to content

Commit

Permalink
Enhance videos page
Browse files Browse the repository at this point in the history
  • Loading branch information
ismartcoding committed May 25, 2024
1 parent e749f5d commit f6bb519
Show file tree
Hide file tree
Showing 92 changed files with 1,562 additions and 1,263 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ android {
ndk {
//noinspection ChromeOsAbiSupport
abiFilters += abiFilterList.ifEmpty {
listOf("arm64-v8a", "x86_64")
listOf("arm64-v8a")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
android:usesCleartextTraffic="true">
<activity
android:name=".ui.MainActivity"
android:configChanges="uiMode|orientation|screenSize|smallestScreenSize|screenLayout"
android:configChanges="uiMode|orientation|screenSize|smallestScreenSize|screenLayout|locale|layoutDirection"
android:exported="true"
android:launchMode="singleInstance"
android:supportsPictureInPicture="true"
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/ismartcoding/plain/SystemServices.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,9 @@ val alarmManager: AlarmManager by lazy {
MainApp.instance.getSystemServiceCompat(AlarmManager::class.java)
}

val audioManager: android.media.AudioManager by lazy {
MainApp.instance.getSystemServiceCompat(android.media.AudioManager::class.java)
}



Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ data class DImageMeta(
val exposureTime: String,
val focalLength : String,
val isoSpeed: Int,
val contentCreated: Instant?,
val takenAt: Instant?,
val flash: Int,
val fNumber: Double,
val exposureProgram: Int,
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/com/ismartcoding/plain/data/DVideoMeta.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.ismartcoding.plain.data

import kotlinx.datetime.Instant

data class DVideoMeta(
val width: Int,
val height: Int,
val rotation: Int,
val duration: Long,
val bitrate: Int,
val bitrate: Long,
val frameRate: Float,
val title: String,
val artist: String,
val album: String,
val genre: String,
val date: String,
val takenAt: Instant?,
val writer: String,
val composer: String,
)
31 changes: 3 additions & 28 deletions app/src/main/java/com/ismartcoding/plain/extensions/Date.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package com.ismartcoding.plain.extensions

import com.ismartcoding.plain.MainApp
import com.ismartcoding.plain.features.locale.LocaleHelper
import com.ismartcoding.plain.helpers.TimeAgoHelper
import kotlinx.datetime.*
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.Calendar
import java.util.Date
import java.util.Locale

fun Date.formatDateTime(): String {
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, LocaleHelper.currentLocale()).format(this)
Expand All @@ -18,31 +18,6 @@ fun Date.formatTime(): String {
return android.text.format.DateFormat.getTimeFormat(MainApp.instance).format(c.time)
}

fun Instant.formatTime(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return android.text.format.DateFormat.getTimeFormat(MainApp.instance)
.format(c.time)
}

fun Instant.formatDateTime(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, LocaleHelper.currentLocale())
.format(c.time)
}

fun Instant.timeAgo(): String {
return TimeAgoHelper.getString(toEpochMilliseconds())
}

fun Instant.formatDate(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleHelper.currentLocale())
.format(c.time)
}

fun Date.formatName(): String {
return SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.ENGLISH).format(this)
}
34 changes: 34 additions & 0 deletions app/src/main/java/com/ismartcoding/plain/extensions/Instant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ismartcoding.plain.extensions

import com.ismartcoding.plain.MainApp
import com.ismartcoding.plain.features.locale.LocaleHelper
import com.ismartcoding.plain.helpers.TimeAgoHelper
import kotlinx.datetime.Instant
import java.text.DateFormat
import java.util.Calendar


fun Instant.formatTime(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return android.text.format.DateFormat.getTimeFormat(MainApp.instance)
.format(c.time)
}

fun Instant.formatDateTime(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, LocaleHelper.currentLocale())
.format(c.time)
}

fun Instant.timeAgo(): String {
return TimeAgoHelper.getString(toEpochMilliseconds())
}

fun Instant.formatDate(): String {
val c = Calendar.getInstance()
c.timeInMillis = epochSeconds * 1000
return DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleHelper.currentLocale())
.format(c.time)
}
29 changes: 0 additions & 29 deletions app/src/main/java/com/ismartcoding/plain/helpers/FormatHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,33 +73,4 @@ object FormatHelper {
format.roundingMode = RoundingMode.HALF_UP
return format.format(value)
}

fun formatDuration(
totalSeconds: Long,
alwaysShowHour: Boolean = false,
): String {
val seconds = totalSeconds % 60
val minutes = totalSeconds / 60 % 60
val hours = totalSeconds / 3600
return if (hours > 0 || alwaysShowHour) {
String.format("%02d:%02d:%02d", hours, minutes, seconds)
} else {
String.format("%02d:%02d", minutes, seconds)
}
}

fun formatBytes(bytes: Long): String {
if (bytes in 0..999) {
return "$bytes B"
}

var newBytes = bytes
val ci = StringCharacterIterator("kMGTPE")
while (newBytes <= -999950 || newBytes >= 999950) {
newBytes /= 1000
ci.next()
}

return String.format("%.1f %cB", newBytes / 1000.0, ci.current())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ object ImageHelper {

try {
val exif = ExifInterface(path)
val contentCreated = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL) ?: return null
val takenAt = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL) ?: return null
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val rotation = when (orientation) {
ExifInterface.ORIENTATION_ROTATE_90 -> 90
Expand Down Expand Up @@ -190,7 +190,7 @@ object ImageHelper {
exposureTimeToString(exposureTime),
focalLength,
isoSpeed,
convertExifDateTimeToInstant(contentCreated),
convertExifDateTimeToInstant(takenAt),
flash,
fNumber,
exposureProgram,
Expand Down
32 changes: 27 additions & 5 deletions app/src/main/java/com/ismartcoding/plain/helpers/VideoHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import android.media.MediaMetadataRetriever
import androidx.compose.ui.unit.IntSize
import com.ismartcoding.lib.logcat.LogCat
import com.ismartcoding.plain.data.DVideoMeta
import kotlinx.datetime.Instant
import java.io.File
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.Locale


object VideoHelper {
Expand All @@ -20,20 +26,19 @@ object VideoHelper {
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toIntOrNull() ?: 0
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull() ?: 0
val rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toIntOrNull() ?: 0
val duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLongOrNull() ?: 0
val bitrate = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)?.toIntOrNull() ?: 0
val duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()?.div(1000) ?: 0L
val bitrate = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)?.toLongOrNull() ?: 0
val frameRate = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE)?.toFloatOrNull() ?: 0f
val title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) ?: ""
val artist = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST) ?: ""
val album = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) ?: ""
val genre = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE) ?: ""
val date = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE) ?: ""
val takenAt = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE)
val writer = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER) ?: ""
val composer = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER) ?: ""

retriever.release()

DVideoMeta(width, height, rotation, duration, bitrate, frameRate, title, artist, album, genre, date, writer, composer)
DVideoMeta(width, height, rotation, duration, bitrate, frameRate, title, artist, album, genre, convertDateTimeToInstant(takenAt), writer, composer)
} catch (e: Exception) {
LogCat.e(e.toString())
null
Expand All @@ -51,4 +56,21 @@ object VideoHelper {
IntSize(w, h)
}
}

private fun convertDateTimeToInstant(dateTime: String?): Instant? {
if (dateTime == null) {
return null
}

try {
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSX")
val localDateTime = LocalDateTime.parse(dateTime, formatter)
val javaInstant = ZonedDateTime.of(localDateTime, ZoneOffset.UTC).toInstant()

return Instant.fromEpochMilliseconds(javaInstant.toEpochMilli())
} catch (ex: Exception) {
LogCat.e(ex.toString())
return null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.View
import android.widget.SeekBar
import androidx.lifecycle.lifecycleScope
import com.ismartcoding.lib.channel.receiveEvent
import com.ismartcoding.lib.extensions.formatDuration
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
import com.ismartcoding.plain.R
import com.ismartcoding.plain.TempData
Expand Down Expand Up @@ -76,13 +77,13 @@ class AudioPlayerDialog() : BaseBottomSheetDialog<DialogAudioPlayerBinding>() {
lifecycleScope.launch {
binding.seekBar.removeCallbacks(seekBarUpdateRunnable)
val process = AudioPlayer.playerProgress / 1000
binding.process.text = FormatHelper.formatDuration(process)
binding.process.text = process.formatDuration()
val path = withIO { AudioPlayingPreference.getValueAsync(requireContext()) }
if (path.isNotEmpty()) {
val audio = withIO { DPlaylistAudio.fromPath(requireContext(), path) }
binding.seekBar.max = audio.duration.toInt()
binding.seekBar.progress = process.toInt()
binding.duration.text = FormatHelper.formatDuration(audio.duration)
binding.duration.text = audio.duration.formatDuration()
binding.title.text = audio.title
binding.title.isSelected = true // need for marquee
binding.artist.text = audio.artist
Expand Down Expand Up @@ -135,14 +136,14 @@ class AudioPlayerDialog() : BaseBottomSheetDialog<DialogAudioPlayerBinding>() {
s.removeCallbacks(seekBarUpdateRunnable)
}

binding.process.text = FormatHelper.formatDuration(s.progress.toLong())
binding.process.text = s.progress.toLong().formatDuration()
}

override fun onStartTrackingTouch(s: SeekBar) = Unit

override fun onStopTrackingTouch(s: SeekBar) {
s.removeCallbacks(seekBarUpdateRunnable)
binding.process.text = FormatHelper.formatDuration(s.progress.toLong())
binding.process.text = s.progress.toLong().formatDuration()
AudioPlayer.seekTo(s.progress.toLong())
s.postDelayed(seekBarUpdateRunnable, seekBarUpdateDelayMillis)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.ismartcoding.lib.brv.utils.removeModel
import com.ismartcoding.lib.brv.utils.setup
import com.ismartcoding.lib.channel.receiveEvent
import com.ismartcoding.lib.channel.sendEvent
import com.ismartcoding.lib.extensions.formatDuration
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
import com.ismartcoding.plain.R
import com.ismartcoding.plain.preference.AudioPlayingPreference
Expand Down Expand Up @@ -161,7 +162,7 @@ class AudioPlaylistDialog : BaseBottomSheetDialog<DialogPlaylistBinding>() {
.map { audio ->
AudioModel(audio).apply {
title = audio.title
subtitle = audio.artist + " " + FormatHelper.formatDuration(audio.duration)
subtitle = audio.artist + " " + audio.duration.formatDuration()
isPlaying = isAudioPlaying && currentPath == audio.path
swipeEnable = true
rightSwipeText = getString(R.string.remove)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.ismartcoding.lib.brv.utils.models
import com.ismartcoding.lib.brv.utils.setup
import com.ismartcoding.lib.channel.receiveEvent
import com.ismartcoding.lib.extensions.dp2px
import com.ismartcoding.lib.extensions.formatDuration
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
import com.ismartcoding.plain.helpers.FormatHelper
import com.ismartcoding.lib.isQPlus
Expand Down Expand Up @@ -205,7 +206,7 @@ class AudiosDialog(private val bucket: DMediaBucket? = null) : BaseListDrawerDia
items.map { a ->
AudioModel(a).apply {
title = a.title
subtitle = a.artist + " " + FormatHelper.formatDuration(a.duration)
subtitle = a.artist + " " + a.duration.formatDuration()
this.toggleMode = toggleMode
isChecked = checkedItems.any { it.data.id == data.id }
isPlaying = isAudioPlaying && currentPath == a.path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.widget.SeekBar
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.ismartcoding.lib.channel.receiveEvent
import com.ismartcoding.lib.extensions.formatDuration
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
import com.ismartcoding.plain.helpers.FormatHelper
import com.ismartcoding.lib.isSPlus
Expand Down Expand Up @@ -41,7 +42,7 @@ class SleepTimerDialog() : BaseBottomSheetDialog<DialogSleepTimerBinding>() {
) {
super.onViewCreated(view, savedInstanceState)

receiveEvent<PermissionsResultEvent> { event ->
receiveEvent<PermissionsResultEvent> {
if (isSPlus()) {
if (alarmManager.canScheduleExactAlarms()) {
alarmManager.setExact(
Expand All @@ -68,7 +69,7 @@ class SleepTimerDialog() : BaseBottomSheetDialog<DialogSleepTimerBinding>() {
if (leftTime > 0) {
binding.seekBar.isVisible = false
binding.shouldFinishLastAudio.isVisible = false
binding.minutes.text = FormatHelper.formatDuration(leftTime / 1000)
binding.minutes.text = (leftTime / 1000).formatDuration()
binding.start.text = getString(R.string.stop)
binding.start.setSafeClick {
lifecycleScope.launch {
Expand Down Expand Up @@ -210,7 +211,7 @@ class SleepTimerDialog() : BaseBottomSheetDialog<DialogSleepTimerBinding>() {
override fun onTick(millisUntilFinished: Long) {
dialog.get()?.let {
if (it.isActive) {
it.binding.minutes.text = FormatHelper.formatDuration(millisUntilFinished / 1000)
it.binding.minutes.text = (millisUntilFinished / 1000).formatDuration()
}
}
}
Expand Down
Loading

0 comments on commit f6bb519

Please sign in to comment.