Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: bump minSdk to 26 #7047

Merged
merged 3 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ android {

defaultConfig {
applicationId = "com.github.libretube"
minSdk = 21
minSdk = 26
targetSdk = 34
versionCode = 59
versionName = "0.27.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@ package com.github.libretube.compat
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build

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 {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && activity.isInPictureInPictureMode
}
fun isPictureInPictureAvailable(context: Context) =
context.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)

fun isInPictureInPictureMode(activity: Activity) = activity.isInPictureInPictureMode

fun setPictureInPictureParams(activity: Activity, params: PictureInPictureParamsCompat) {
if (isPictureInPictureAvailable(activity)) {
Expand Down
20 changes: 3 additions & 17 deletions app/src/main/java/com/github/libretube/extensions/FormatShort.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
package com.github.libretube.extensions

import android.icu.text.CompactDecimalFormat
import android.os.Build
import com.github.libretube.helpers.LocaleHelper
import kotlin.math.pow

fun Long?.formatShort(): String {
val value = this ?: 0
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
CompactDecimalFormat
.getInstance(LocaleHelper.getAppLocale(), CompactDecimalFormat.CompactStyle.SHORT)
.format(value)
} 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()
}
}
fun Long?.formatShort(): String = CompactDecimalFormat
.getInstance(LocaleHelper.getAppLocale(), CompactDecimalFormat.CompactStyle.SHORT)
.format(this ?: 0)
15 changes: 1 addition & 14 deletions app/src/main/java/com/github/libretube/helpers/DisplayHelper.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
package com.github.libretube.helpers

import android.content.Context
import android.os.Build
import androidx.core.content.ContextCompat

object DisplayHelper {
/**
* Detect whether the device supports HDR as the ExoPlayer doesn't handle it properly
* Returns false below SDK 24
*/
fun supportsHdr(context: Context): Boolean {
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
}
}
fun supportsHdr(context: Context) = ContextCompat.getDisplayOrDefault(context).isHdr
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.github.libretube.helpers

import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.core.os.bundleOf
Expand Down Expand Up @@ -40,15 +39,12 @@ object DownloadHelper {
private const val VIDEO_MIMETYPE = "video/*"

fun getDownloadDir(context: Context, path: String): Path {
val storageDir = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
context.filesDir
} else {
val storageDir =
try {
context.getExternalFilesDir(null)!!
} catch (e: Exception) {
context.filesDir
}
}
return (storageDir.toPath() / path).createDirectories()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.github.libretube.helpers

import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.telephony.TelephonyManager
import androidx.core.content.getSystemService
import androidx.core.os.ConfigurationCompat
Expand All @@ -29,7 +28,7 @@ object LocaleHelper {

fun updateLanguage(context: Context) {
val locale = getAppLocale()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) updateResources(context, locale)
Pittvandewitt marked this conversation as resolved.
Show resolved Hide resolved
updateResources(context, locale)
updateResourcesLegacy(context, locale)
}

Expand Down
17 changes: 4 additions & 13 deletions app/src/main/java/com/github/libretube/helpers/NetworkHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,20 @@ package com.github.libretube.helpers
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.core.content.getSystemService

object NetworkHelper {
/**
* Detect whether network is available
*/
@Suppress("DEPRECATION")
fun isNetworkAvailable(context: Context): Boolean {
// In case we are using a VPN, we return true since we might be using reverse tethering
val connectivityManager = context.getSystemService<ConnectivityManager>() ?: return false

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork
val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ||
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
}
val activeNetwork = connectivityManager.activeNetwork
val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ||
caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
}

/**
Expand Down
14 changes: 2 additions & 12 deletions app/src/main/java/com/github/libretube/helpers/ThemeHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import android.text.Spanned
import android.view.Window
import androidx.annotation.ColorInt
Expand Down Expand Up @@ -35,12 +34,7 @@ object ThemeHelper {
* Set the background color of the status bar
*/
private fun setStatusBarColor(context: Context, window: Window) {
window.statusBarColor =
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)
}
window.statusBarColor = getThemeColor(context, android.R.attr.colorBackground)
WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = !isDarkMode(context)
}
Expand All @@ -54,11 +48,7 @@ object ThemeHelper {
@ColorInt bottomNavColor: Int?
) {
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)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.github.libretube.ui.base

import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.github.libretube.R
Expand Down Expand Up @@ -40,11 +39,6 @@ open class BaseActivity : AppCompatActivity() {
ThemeHelper.updateTheme(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
LocaleHelper.updateLanguage(this)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,27 +733,23 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
DownloadHelper.startDownloadDialog(requireContext(), childFragmentManager, videoId)
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
binding.relPlayerScreenshot.setOnClickListener {
if (!this::streams.isInitialized) return@setOnClickListener
val surfaceView =
binding.player.videoSurfaceView as? SurfaceView ?: return@setOnClickListener

val bmp = Bitmap.createBitmap(
surfaceView.width,
surfaceView.height,
Bitmap.Config.ARGB_8888
)
binding.relPlayerScreenshot.setOnClickListener {
if (!this::streams.isInitialized) return@setOnClickListener
val surfaceView =
binding.player.videoSurfaceView as? SurfaceView ?: return@setOnClickListener

PixelCopy.request(surfaceView, bmp, { _ ->
screenshotBitmap = bmp
val currentPosition =
playerController.currentPosition.toFloat() / 1000
openScreenshotFile.launch("${streams.title}-${currentPosition}.png")
}, Handler(Looper.getMainLooper()))
}
} else {
binding.relPlayerScreenshot.isGone = true
val bmp = Bitmap.createBitmap(
surfaceView.width,
surfaceView.height,
Bitmap.Config.ARGB_8888
)

PixelCopy.request(surfaceView, bmp, { _ ->
screenshotBitmap = bmp
val currentPosition =
playerController.currentPosition.toFloat() / 1000
openScreenshotFile.launch("${streams.title}-${currentPosition}.png")
}, Handler(Looper.getMainLooper()))
}

binding.playerChannel.setOnClickListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class DescriptionLayout(
this.streams = streams

val views = streams.views.formatShort()
val date = TextUtils.formatRelativeDate(context, streams.uploaded ?: -1L)
val date = TextUtils.formatRelativeDate(streams.uploaded ?: -1L)
binding.run {
playerViewsInfo.text = context.getString(R.string.normal_views, views, TextUtils.SEPARATOR + date)

Expand Down Expand Up @@ -135,7 +135,7 @@ class DescriptionLayout(
val isNewStateExpanded = binding.descLinLayout.isGone
if (!isNewStateExpanded) {
// 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)

// limit the title height to two lines
Expand Down
24 changes: 7 additions & 17 deletions app/src/main/java/com/github/libretube/util/TextUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.github.libretube.util
import android.content.Context
import android.icu.text.RelativeDateTimeFormatter
import android.net.Uri
import android.os.Build
import android.text.format.DateUtils
import androidx.core.text.isDigitsOnly
import com.github.libretube.BuildConfig
Expand Down Expand Up @@ -111,30 +110,21 @@ object TextUtils {
else -> null
}

fun formatRelativeDate(context: Context, unixTime: Long): CharSequence {
fun formatRelativeDate(unixTime: Long): CharSequence {
val date = LocalDateTime.ofInstant(Instant.ofEpochMilli(unixTime), ZoneId.systemDefault())
val now = LocalDateTime.now()
val months = date.until(now, ChronoUnit.MONTHS)

return if (months > 0) {
val years = months / 12

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val (timeFormat, time) = if (years > 0) {
RelativeDateTimeFormatter.RelativeUnit.YEARS to years
} else {
RelativeDateTimeFormatter.RelativeUnit.MONTHS to months
}
RelativeDateTimeFormatter.getInstance()
.format(time.toDouble(), RelativeDateTimeFormatter.Direction.LAST, timeFormat)
val (timeFormat, time) = if (years > 0) {
RelativeDateTimeFormatter.RelativeUnit.YEARS to years
} else {
val (timeAgoRes, time) = if (years > 0) {
R.plurals.years_ago to years
} else {
R.plurals.months_ago to months
Pittvandewitt marked this conversation as resolved.
Show resolved Hide resolved
}
context.resources.getQuantityString(timeAgoRes, time.toInt(), time)
RelativeDateTimeFormatter.RelativeUnit.MONTHS to months
}
RelativeDateTimeFormatter.getInstance()
.format(time.toDouble(), RelativeDateTimeFormatter.Direction.LAST, timeFormat)
} else {
val weeks = date.until(now, ChronoUnit.WEEKS)
val minResolution = if (weeks > 0) DateUtils.WEEK_IN_MILLIS else 0L
Expand All @@ -161,7 +151,7 @@ object TextUtils {
context.getString(R.string.view_count, it)
}
val uploadDate = uploaded.takeIf { it > 0 }?.let {
formatRelativeDate(context, it)
formatRelativeDate(it)
}
return listOfNotNull(uploader, viewsString, uploadDate).joinToString(SEPARATOR)
}
Expand Down
Loading