mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 14:20:30 +05:30
Merge branch 'master' into weblate-libretube-libretube
This commit is contained in:
commit
1d0f7f7f07
@ -9,7 +9,7 @@
|
|||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MyApp"
|
android:name=".LibreTubeApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import android.os.StrictMode.VmPolicy
|
import android.os.StrictMode.VmPolicy
|
||||||
|
import androidx.core.app.NotificationChannelCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
import com.github.libretube.api.CronetHelper
|
import com.github.libretube.api.CronetHelper
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
@ -19,12 +17,12 @@ import com.github.libretube.util.ImageHelper
|
|||||||
import com.github.libretube.util.NotificationHelper
|
import com.github.libretube.util.NotificationHelper
|
||||||
import com.github.libretube.util.PreferenceHelper
|
import com.github.libretube.util.PreferenceHelper
|
||||||
|
|
||||||
class MyApp : Application() {
|
class LibreTubeApp : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the needed [NotificationChannel]s for DownloadService and BackgroundMode
|
* Initialize the needed notification channels for DownloadService and BackgroundMode
|
||||||
*/
|
*/
|
||||||
initializeNotificationChannels()
|
initializeNotificationChannels()
|
||||||
|
|
||||||
@ -67,47 +65,38 @@ class MyApp : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the required [NotificationChannel]s for the app.
|
* Initializes the required notification channels for the app.
|
||||||
*/
|
*/
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private fun initializeNotificationChannels() {
|
private fun initializeNotificationChannels() {
|
||||||
createNotificationChannel(
|
val downloadChannel = NotificationChannelCompat.Builder(
|
||||||
DOWNLOAD_CHANNEL_ID,
|
DOWNLOAD_CHANNEL_ID,
|
||||||
"Download Service",
|
NotificationManagerCompat.IMPORTANCE_NONE
|
||||||
"Shows a notification when downloading media.",
|
|
||||||
NotificationManager.IMPORTANCE_NONE
|
|
||||||
)
|
)
|
||||||
createNotificationChannel(
|
.setName(getString(R.string.download_channel_name))
|
||||||
|
.setDescription(getString(R.string.download_channel_description))
|
||||||
|
.build()
|
||||||
|
val backgroundChannel = NotificationChannelCompat.Builder(
|
||||||
BACKGROUND_CHANNEL_ID,
|
BACKGROUND_CHANNEL_ID,
|
||||||
"Background Mode",
|
NotificationManagerCompat.IMPORTANCE_LOW
|
||||||
"Shows a notification with buttons to control the audio player",
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
)
|
)
|
||||||
createNotificationChannel(
|
.setName(getString(R.string.background_channel_name))
|
||||||
|
.setDescription(getString(R.string.background_channel_description))
|
||||||
|
.build()
|
||||||
|
val pushChannel = NotificationChannelCompat.Builder(
|
||||||
PUSH_CHANNEL_ID,
|
PUSH_CHANNEL_ID,
|
||||||
"Notification Worker",
|
NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||||
"Shows a notification when new streams are available.",
|
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
|
||||||
)
|
)
|
||||||
}
|
.setName(getString(R.string.push_channel_name))
|
||||||
|
.setDescription(getString(R.string.push_channel_description))
|
||||||
|
.build()
|
||||||
|
|
||||||
/**
|
val notificationManager = NotificationManagerCompat.from(this)
|
||||||
* Creates a [NotificationChannel]
|
notificationManager.createNotificationChannelsCompat(
|
||||||
*/
|
listOf(
|
||||||
private fun createNotificationChannel(
|
downloadChannel,
|
||||||
id: String,
|
backgroundChannel,
|
||||||
name: String,
|
pushChannel
|
||||||
descriptionText: String,
|
)
|
||||||
importance: Int
|
)
|
||||||
) {
|
|
||||||
// Create the NotificationChannel, but only on API 26+ because
|
|
||||||
// the NotificationChannel class is new and not in the support library
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val channel = NotificationChannel(id, name, importance)
|
|
||||||
channel.description = descriptionText
|
|
||||||
// Register the channel in the system
|
|
||||||
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
notificationManager.createNotificationChannel(channel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -165,8 +165,6 @@ class MainActivity : BaseActivity() {
|
|||||||
// new way of handling back presses
|
// new way of handling back presses
|
||||||
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
|
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
navController.popBackStack(R.id.searchFragment, false)
|
|
||||||
|
|
||||||
if (binding.mainMotionLayout.progress == 0F) {
|
if (binding.mainMotionLayout.progress == 0F) {
|
||||||
try {
|
try {
|
||||||
minimizePlayer()
|
minimizePlayer()
|
||||||
@ -289,6 +287,13 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
|
// prevent malicious navigation when the search view is getting collapsed
|
||||||
|
if (navController.currentDestination?.id == R.id.searchResultFragment &&
|
||||||
|
(newText == null || newText == "")
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (navController.currentDestination?.id != R.id.searchFragment) {
|
if (navController.currentDestination?.id != R.id.searchFragment) {
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString("query", newText)
|
bundle.putString("query", newText)
|
||||||
@ -296,6 +301,7 @@ class MainActivity : BaseActivity() {
|
|||||||
} else {
|
} else {
|
||||||
searchViewModel.setQuery(newText)
|
searchViewModel.setQuery(newText)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -75,6 +75,7 @@ object PreferenceKeys {
|
|||||||
const val SKIP_BUTTONS = "skip_buttons"
|
const val SKIP_BUTTONS = "skip_buttons"
|
||||||
const val PICTURE_IN_PICTURE = "picture_in_picture"
|
const val PICTURE_IN_PICTURE = "picture_in_picture"
|
||||||
const val PLAYER_RESIZE_MODE = "player_resize_mode"
|
const val PLAYER_RESIZE_MODE = "player_resize_mode"
|
||||||
|
const val SB_SKIP_MANUALLY = "sb_skip_manually_key"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Background mode
|
* Background mode
|
||||||
|
@ -169,6 +169,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
private var sponsorBlockNotifications = true
|
private var sponsorBlockNotifications = true
|
||||||
private var skipButtonsEnabled = false
|
private var skipButtonsEnabled = false
|
||||||
private var pipEnabled = true
|
private var pipEnabled = true
|
||||||
|
private var skipSegmentsManually = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for autoplay
|
* for autoplay
|
||||||
@ -336,6 +337,11 @@ class PlayerFragment : BaseFragment() {
|
|||||||
PreferenceKeys.PICTURE_IN_PICTURE,
|
PreferenceKeys.PICTURE_IN_PICTURE,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
skipSegmentsManually = PreferenceHelper.getBoolean(
|
||||||
|
PreferenceKeys.SB_SKIP_MANUALLY,
|
||||||
|
false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@ -709,21 +715,39 @@ class PlayerFragment : BaseFragment() {
|
|||||||
|
|
||||||
Handler(Looper.getMainLooper()).postDelayed(this::checkForSegments, 100)
|
Handler(Looper.getMainLooper()).postDelayed(this::checkForSegments, 100)
|
||||||
|
|
||||||
if (!::segmentData.isInitialized || segmentData.segments.isEmpty()) {
|
if (!::segmentData.isInitialized || segmentData.segments.isEmpty()) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val currentPosition = exoPlayer.currentPosition
|
||||||
segmentData.segments.forEach { segment: Segment ->
|
segmentData.segments.forEach { segment: Segment ->
|
||||||
val segmentStart = (segment.segment!![0] * 1000f).toLong()
|
val segmentStart = (segment.segment!![0] * 1000f).toLong()
|
||||||
val segmentEnd = (segment.segment[1] * 1000f).toLong()
|
val segmentEnd = (segment.segment[1] * 1000f).toLong()
|
||||||
val currentPosition = exoPlayer.currentPosition
|
|
||||||
|
// show the button to manually skip the segment
|
||||||
if (currentPosition in segmentStart until segmentEnd) {
|
if (currentPosition in segmentStart until segmentEnd) {
|
||||||
if (sponsorBlockNotifications) {
|
if (skipSegmentsManually) {
|
||||||
Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT).show()
|
binding.sbSkipBtn.visibility = View.VISIBLE
|
||||||
|
binding.sbSkipBtn.setOnClickListener {
|
||||||
|
exoPlayer.seekTo(segmentEnd)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sponsorBlockNotifications) {
|
||||||
|
Toast
|
||||||
|
.makeText(
|
||||||
|
context,
|
||||||
|
R.string.segment_skipped,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip the segment automatically
|
||||||
exoPlayer.seekTo(segmentEnd)
|
exoPlayer.seekTo(segmentEnd)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skipSegmentsManually) binding.sbSkipBtn.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playVideo() {
|
private fun playVideo() {
|
||||||
@ -743,6 +767,9 @@ class PlayerFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
|
// hide the button to skip SponsorBlock segments manually
|
||||||
|
binding.sbSkipBtn.visibility = View.GONE
|
||||||
|
|
||||||
// set media sources for the player
|
// set media sources for the player
|
||||||
setResolutionAndSubtitles()
|
setResolutionAndSubtitles()
|
||||||
prepareExoPlayerView()
|
prepareExoPlayerView()
|
||||||
|
@ -378,8 +378,44 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
</com.github.libretube.views.CustomExoPlayerView>
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="-10dp"
|
||||||
|
android:layout_marginBottom="60dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
app:cardBackgroundColor="#88000000"
|
||||||
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/sb_skip_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/skip_segment"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:src="@drawable/ic_next"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</com.github.libretube.views.CustomExoPlayerView>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/close_imageView"
|
android:id="@+id/close_imageView"
|
||||||
|
@ -321,4 +321,15 @@
|
|||||||
<string name="mobile_data">Mobile data</string>
|
<string name="mobile_data">Mobile data</string>
|
||||||
<string name="new_videos_badge">Indicator for new videos</string>
|
<string name="new_videos_badge">Indicator for new videos</string>
|
||||||
<string name="new_videos_badge_summary">Show a badge with the amount of new videos if there are some.</string>
|
<string name="new_videos_badge_summary">Show a badge with the amount of new videos if there are some.</string>
|
||||||
</resources>
|
<string name="skip_segment">Skip segment</string>
|
||||||
|
<string name="sb_skip_manual">Skip manually</string>
|
||||||
|
<string name="sb_skip_manual_summary">Don\'t skip segments automatically, always prompt before.</string>
|
||||||
|
|
||||||
|
<!-- Notification channel strings -->
|
||||||
|
<string name="download_channel_name">Download Service</string>
|
||||||
|
<string name="download_channel_description">Shows a notification when downloading media.</string>
|
||||||
|
<string name="background_channel_name">Background Mode</string>
|
||||||
|
<string name="background_channel_description">Shows a notification with buttons to control the audio player.</string>
|
||||||
|
<string name="push_channel_name">Notification Worker</string>
|
||||||
|
<string name="push_channel_description">Shows a notification when new streams are available.</string>
|
||||||
|
</resources>
|
||||||
|
@ -16,6 +16,12 @@
|
|||||||
app:key="sb_notifications_key"
|
app:key="sb_notifications_key"
|
||||||
app:title="@string/sponsorblock_notifications" />
|
app:title="@string/sponsorblock_notifications" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:summary="@string/sb_skip_manual_summary"
|
||||||
|
app:defaultValue="false"
|
||||||
|
app:key="sb_skip_manually_key"
|
||||||
|
app:title="@string/sb_skip_manual" />
|
||||||
|
|
||||||
<PreferenceCategory app:title="@string/category_segments">
|
<PreferenceCategory app:title="@string/category_segments">
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
|
Loading…
Reference in New Issue
Block a user