Bump minSdk to 26

This commit is contained in:
Thomas 2025-01-29 20:37:49 +01:00
parent cde9bc33e5
commit 4adcbb9719
12 changed files with 41 additions and 116 deletions

View File

@ -13,7 +13,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "com.github.libretube" applicationId = "com.github.libretube"
minSdk = 21 minSdk = 26
targetSdk = 34 targetSdk = 34
versionCode = 59 versionCode = 59
versionName = "0.27.0" versionName = "0.27.0"

View File

@ -3,17 +3,13 @@ package com.github.libretube.compat
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build
object PictureInPictureCompat { object PictureInPictureCompat {
fun isPictureInPictureAvailable(context: Context): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
context.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
}
fun isInPictureInPictureMode(activity: Activity): Boolean { fun isPictureInPictureAvailable(context: Context) =
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && activity.isInPictureInPictureMode context.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
}
fun isInPictureInPictureMode(activity: Activity) = activity.isInPictureInPictureMode
fun setPictureInPictureParams(activity: Activity, params: PictureInPictureParamsCompat) { fun setPictureInPictureParams(activity: Activity, params: PictureInPictureParamsCompat) {
if (isPictureInPictureAvailable(activity)) { if (isPictureInPictureAvailable(activity)) {

View File

@ -1,22 +1,8 @@
package com.github.libretube.extensions package com.github.libretube.extensions
import android.icu.text.CompactDecimalFormat import android.icu.text.CompactDecimalFormat
import android.os.Build
import com.github.libretube.helpers.LocaleHelper import com.github.libretube.helpers.LocaleHelper
import kotlin.math.pow
fun Long?.formatShort(): String { fun Long?.formatShort(): String = CompactDecimalFormat
val value = this ?: 0
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
CompactDecimalFormat
.getInstance(LocaleHelper.getAppLocale(), CompactDecimalFormat.CompactStyle.SHORT) .getInstance(LocaleHelper.getAppLocale(), CompactDecimalFormat.CompactStyle.SHORT)
.format(value) .format(this ?: 0)
} else {
val units = arrayOf("", "K", "M", "B", "T")
for (i in units.size downTo 1) {
val step = 1000.0.pow(i.toDouble())
if (value > step) return "%3.0f%s".format(value / step, units[i]).trim()
}
value.toString()
}
}

View File

@ -1,7 +1,6 @@
package com.github.libretube.helpers package com.github.libretube.helpers
import android.content.Context import android.content.Context
import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
object DisplayHelper { object DisplayHelper {
@ -9,17 +8,5 @@ object DisplayHelper {
* Detect whether the device supports HDR as the ExoPlayer doesn't handle it properly * Detect whether the device supports HDR as the ExoPlayer doesn't handle it properly
* Returns false below SDK 24 * Returns false below SDK 24
*/ */
fun supportsHdr(context: Context): Boolean { fun supportsHdr(context: Context) = ContextCompat.getDisplayOrDefault(context).isHdr
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val display = ContextCompat.getDisplayOrDefault(context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
display.isHdr
} else {
@Suppress("DEPRECATION")
display.hdrCapabilities?.supportedHdrTypes?.isNotEmpty() ?: false
}
} else {
false
}
}
} }

View File

@ -2,7 +2,6 @@ package com.github.libretube.helpers
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -40,15 +39,12 @@ object DownloadHelper {
private const val VIDEO_MIMETYPE = "video/*" private const val VIDEO_MIMETYPE = "video/*"
fun getDownloadDir(context: Context, path: String): Path { fun getDownloadDir(context: Context, path: String): Path {
val storageDir = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { val storageDir =
context.filesDir
} else {
try { try {
context.getExternalFilesDir(null)!! context.getExternalFilesDir(null)!!
} catch (e: Exception) { } catch (e: Exception) {
context.filesDir context.filesDir
} }
}
return (storageDir.toPath() / path).createDirectories() return (storageDir.toPath() / path).createDirectories()
} }

View File

@ -2,7 +2,6 @@ package com.github.libretube.helpers
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
@ -29,7 +28,7 @@ object LocaleHelper {
fun updateLanguage(context: Context) { fun updateLanguage(context: Context) {
val locale = getAppLocale() val locale = getAppLocale()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) updateResources(context, locale) updateResources(context, locale)
updateResourcesLegacy(context, locale) updateResourcesLegacy(context, locale)
} }

View File

@ -3,29 +3,20 @@ package com.github.libretube.helpers
import android.content.Context import android.content.Context
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.os.Build
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
object NetworkHelper { object NetworkHelper {
/** /**
* Detect whether network is available * Detect whether network is available
*/ */
@Suppress("DEPRECATION")
fun isNetworkAvailable(context: Context): Boolean { fun isNetworkAvailable(context: Context): Boolean {
// In case we are using a VPN, we return true since we might be using reverse tethering // In case we are using a VPN, we return true since we might be using reverse tethering
val connectivityManager = context.getSystemService<ConnectivityManager>() ?: return false val connectivityManager = context.getSystemService<ConnectivityManager>() ?: return false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork val activeNetwork = connectivityManager.activeNetwork
val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) || return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ||
caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
} else {
// activeNetworkInfo might return null instead of the VPN, so better check it explicitly
val networkInfo = connectivityManager.activeNetworkInfo
?: connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_VPN)
return networkInfo?.isConnected == true
}
} }
/** /**

View File

@ -6,7 +6,6 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.os.Build
import android.text.Spanned import android.text.Spanned
import android.view.Window import android.view.Window
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
@ -35,12 +34,7 @@ object ThemeHelper {
* Set the background color of the status bar * Set the background color of the status bar
*/ */
private fun setStatusBarColor(context: Context, window: Window) { private fun setStatusBarColor(context: Context, window: Window) {
window.statusBarColor = window.statusBarColor = getThemeColor(context, android.R.attr.colorBackground)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && !isDarkMode(context)) {
getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
} else {
getThemeColor(context, android.R.attr.colorBackground)
}
WindowCompat.getInsetsController(window, window.decorView) WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = !isDarkMode(context) .isAppearanceLightStatusBars = !isDarkMode(context)
} }
@ -54,12 +48,8 @@ object ThemeHelper {
@ColorInt bottomNavColor: Int? @ColorInt bottomNavColor: Int?
) { ) {
window.navigationBarColor = window.navigationBarColor =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && !isDarkMode(context)) {
getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
} else {
bottomNavColor ?: getThemeColor(context, android.R.attr.colorBackground) bottomNavColor ?: getThemeColor(context, android.R.attr.colorBackground)
} }
}
/** /**
* Set the theme, including accent color and night mode * Set the theme, including accent color and night mode

View File

@ -1,7 +1,6 @@
package com.github.libretube.ui.base package com.github.libretube.ui.base
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.github.libretube.R import com.github.libretube.R
@ -40,11 +39,6 @@ open class BaseActivity : AppCompatActivity() {
ThemeHelper.updateTheme(this) ThemeHelper.updateTheme(this)
if (isDialogActivity) ThemeHelper.applyDialogActivityTheme(this) if (isDialogActivity) ThemeHelper.applyDialogActivityTheme(this)
// Set the navigation and statusBar color if SDK < 23
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
ThemeHelper.setSystemBarColors(this, window)
}
// set the apps language // set the apps language
LocaleHelper.updateLanguage(this) LocaleHelper.updateLanguage(this)

View File

@ -733,7 +733,6 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
DownloadHelper.startDownloadDialog(requireContext(), childFragmentManager, videoId) DownloadHelper.startDownloadDialog(requireContext(), childFragmentManager, videoId)
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
binding.relPlayerScreenshot.setOnClickListener { binding.relPlayerScreenshot.setOnClickListener {
if (!this::streams.isInitialized) return@setOnClickListener if (!this::streams.isInitialized) return@setOnClickListener
val surfaceView = val surfaceView =
@ -752,9 +751,6 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
openScreenshotFile.launch("${streams.title}-${currentPosition}.png") openScreenshotFile.launch("${streams.title}-${currentPosition}.png")
}, Handler(Looper.getMainLooper())) }, Handler(Looper.getMainLooper()))
} }
} else {
binding.relPlayerScreenshot.isGone = true
}
binding.playerChannel.setOnClickListener { binding.playerChannel.setOnClickListener {
if (!this::streams.isInitialized) return@setOnClickListener if (!this::streams.isInitialized) return@setOnClickListener

View File

@ -68,7 +68,7 @@ class DescriptionLayout(
this.streams = streams this.streams = streams
val views = streams.views.formatShort() val views = streams.views.formatShort()
val date = TextUtils.formatRelativeDate(context, streams.uploaded ?: -1L) val date = TextUtils.formatRelativeDate(streams.uploaded ?: -1L)
binding.run { binding.run {
playerViewsInfo.text = context.getString(R.string.normal_views, views, TextUtils.SEPARATOR + date) playerViewsInfo.text = context.getString(R.string.normal_views, views, TextUtils.SEPARATOR + date)
@ -135,7 +135,7 @@ class DescriptionLayout(
val isNewStateExpanded = binding.descLinLayout.isGone val isNewStateExpanded = binding.descLinLayout.isGone
if (!isNewStateExpanded) { if (!isNewStateExpanded) {
// show a short version of the view count and date // show a short version of the view count and date
val formattedDate = TextUtils.formatRelativeDate(context, streams.uploaded ?: -1L) val formattedDate = TextUtils.formatRelativeDate(streams.uploaded ?: -1L)
binding.playerViewsInfo.text = context.getString(R.string.normal_views, streams.views.formatShort(), TextUtils.SEPARATOR + formattedDate) binding.playerViewsInfo.text = context.getString(R.string.normal_views, streams.views.formatShort(), TextUtils.SEPARATOR + formattedDate)
// limit the title height to two lines // limit the title height to two lines

View File

@ -3,7 +3,6 @@ package com.github.libretube.util
import android.content.Context import android.content.Context
import android.icu.text.RelativeDateTimeFormatter import android.icu.text.RelativeDateTimeFormatter
import android.net.Uri import android.net.Uri
import android.os.Build
import android.text.format.DateUtils import android.text.format.DateUtils
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import com.github.libretube.BuildConfig import com.github.libretube.BuildConfig
@ -111,7 +110,7 @@ object TextUtils {
else -> null else -> null
} }
fun formatRelativeDate(context: Context, unixTime: Long): CharSequence { fun formatRelativeDate(unixTime: Long): CharSequence {
val date = LocalDateTime.ofInstant(Instant.ofEpochMilli(unixTime), ZoneId.systemDefault()) val date = LocalDateTime.ofInstant(Instant.ofEpochMilli(unixTime), ZoneId.systemDefault())
val now = LocalDateTime.now() val now = LocalDateTime.now()
val months = date.until(now, ChronoUnit.MONTHS) val months = date.until(now, ChronoUnit.MONTHS)
@ -119,7 +118,6 @@ object TextUtils {
return if (months > 0) { return if (months > 0) {
val years = months / 12 val years = months / 12
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val (timeFormat, time) = if (years > 0) { val (timeFormat, time) = if (years > 0) {
RelativeDateTimeFormatter.RelativeUnit.YEARS to years RelativeDateTimeFormatter.RelativeUnit.YEARS to years
} else { } else {
@ -127,14 +125,6 @@ object TextUtils {
} }
RelativeDateTimeFormatter.getInstance() RelativeDateTimeFormatter.getInstance()
.format(time.toDouble(), RelativeDateTimeFormatter.Direction.LAST, timeFormat) .format(time.toDouble(), RelativeDateTimeFormatter.Direction.LAST, timeFormat)
} else {
val (timeAgoRes, time) = if (years > 0) {
R.plurals.years_ago to years
} else {
R.plurals.months_ago to months
}
context.resources.getQuantityString(timeAgoRes, time.toInt(), time)
}
} else { } else {
val weeks = date.until(now, ChronoUnit.WEEKS) val weeks = date.until(now, ChronoUnit.WEEKS)
val minResolution = if (weeks > 0) DateUtils.WEEK_IN_MILLIS else 0L val minResolution = if (weeks > 0) DateUtils.WEEK_IN_MILLIS else 0L
@ -161,7 +151,7 @@ object TextUtils {
context.getString(R.string.view_count, it) context.getString(R.string.view_count, it)
} }
val uploadDate = uploaded.takeIf { it > 0 }?.let { val uploadDate = uploaded.takeIf { it > 0 }?.let {
formatRelativeDate(context, it) formatRelativeDate(it)
} }
return listOfNotNull(uploader, viewsString, uploadDate).joinToString(SEPARATOR) return listOfNotNull(uploader, viewsString, uploadDate).joinToString(SEPARATOR)
} }