Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay

This commit is contained in:
Kelvin 2024-11-12 15:03:08 +01:00
commit 4a708e316a
10 changed files with 95 additions and 38 deletions

View file

@ -882,7 +882,10 @@ class Settings : FragmentedStorageFileJson() {
@FormFieldWarning(R.string.bypass_rotation_prevention_warning)
var bypassRotationPrevention: Boolean = false;
@FormField(R.string.enable_polycentric, FieldForm.TOGGLE, R.string.can_be_disabled_when_you_are_experiencing_issues, 1)
@FormField(R.string.playlist_delete_confirmation, FieldForm.TOGGLE, R.string.playlist_delete_confirmation_description, 2)
var playlistDeleteConfirmation: Boolean = true;
@FormField(R.string.enable_polycentric, FieldForm.TOGGLE, R.string.can_be_disabled_when_you_are_experiencing_issues, 3)
var polycentricEnabled: Boolean = true;
}

View file

@ -348,6 +348,13 @@ class UIDialogs {
showDialog(context, R.drawable.ic_error, text, null, null, 0, cancelButtonAction, confirmButtonAction)
}
fun showConfirmationDialog(context: Context, text: String, action: () -> Unit, cancelAction: (() -> Unit)? = null, doNotAskAgainAction: (() -> Unit)? = null) {
val confirmButtonAction = Action(context.getString(R.string.confirm), action, ActionStyle.PRIMARY)
val cancelButtonAction = Action(context.getString(R.string.cancel), cancelAction ?: {}, ActionStyle.ACCENT)
val doNotAskAgain = Action(context.getString(R.string.do_not_ask_again), doNotAskAgainAction ?: {}, ActionStyle.NONE)
showDialog(context, R.drawable.ic_error, text, null, null, 0, doNotAskAgain, cancelButtonAction, confirmButtonAction)
}
fun showUpdateAvailableDialog(context: Context, lastVersion: Int, hideExceptionButtons: Boolean = false) {
val dialog = AutoUpdateDialog(context);
registerDialogOpened(dialog);

View file

@ -101,7 +101,7 @@ class VideoDetailFragment : MainFragment {
val currentRequestedOrientation = a.requestedOrientation
var currentOrientation = if (_currentOrientation == -1) currentRequestedOrientation else _currentOrientation
if (currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT && !Settings.instance.playback.reversePortrait)
currentOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
currentOrientation = currentRequestedOrientation
val isAutoRotate = Settings.instance.playback.isAutoRotate()
val isFs = isFullscreen
@ -347,7 +347,7 @@ class VideoDetailFragment : MainFragment {
return true
}
if (state == State.MAXIMIZED && isFullscreen && !Settings.instance.playback.fullscreenPortrait && (_currentOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || _currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT)) {
if (state == State.MAXIMIZED && isFullscreen && !Settings.instance.playback.fullscreenPortrait && (_currentOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || (Settings.instance.playback.reversePortrait && _currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT))) {
_viewDetail?.setFullscreen(false)
return true
}

View file

@ -46,7 +46,10 @@ class MDNSListener {
}
fun start() {
if (_started) throw Exception("Already running.")
if (_started) {
Logger.i(TAG, "Already started.")
return
}
_started = true
_scope = CoroutineScope(Dispatchers.IO);

View file

@ -100,33 +100,34 @@ class ServiceRecordAggregator {
Logger.i(TAG, "$builder")*/
val currentServices: MutableList<DnsService>
ptrRecords.forEach { record ->
val cachedPtrRecord = _cachedPtrRecords.getOrPut(record.first.name) { mutableListOf() }
val newPtrRecord = CachedDnsPtrRecord(Date(System.currentTimeMillis() + record.first.timeToLive.toLong() * 1000L), record.second.domainName)
cachedPtrRecord.replaceOrAdd(newPtrRecord) { it.target == record.second.domainName }
}
aRecords.forEach { aRecord ->
val cachedARecord = _cachedAddressRecords.getOrPut(aRecord.first.name) { mutableListOf() }
val newARecord = CachedDnsAddressRecord(Date(System.currentTimeMillis() + aRecord.first.timeToLive.toLong() * 1000L), aRecord.second.address)
cachedARecord.replaceOrAdd(newARecord) { it.address == newARecord.address }
}
aaaaRecords.forEach { aaaaRecord ->
val cachedAaaaRecord = _cachedAddressRecords.getOrPut(aaaaRecord.first.name) { mutableListOf() }
val newAaaaRecord = CachedDnsAddressRecord(Date(System.currentTimeMillis() + aaaaRecord.first.timeToLive.toLong() * 1000L), aaaaRecord.second.address)
cachedAaaaRecord.replaceOrAdd(newAaaaRecord) { it.address == newAaaaRecord.address }
}
txtRecords.forEach { txtRecord ->
_cachedTxtRecords[txtRecord.first.name] = CachedDnsTxtRecord(Date(System.currentTimeMillis() + txtRecord.first.timeToLive.toLong() * 1000L), txtRecord.second.texts)
}
srvRecords.forEach { srvRecord ->
_cachedSrvRecords[srvRecord.first.name] = CachedDnsSrvRecord(Date(System.currentTimeMillis() + srvRecord.first.timeToLive.toLong() * 1000L), srvRecord.second)
}
//TODO: Maybe this can be debounced?
synchronized(this._currentServices) {
ptrRecords.forEach { record ->
val cachedPtrRecord = _cachedPtrRecords.getOrPut(record.first.name) { mutableListOf() }
val newPtrRecord = CachedDnsPtrRecord(Date(System.currentTimeMillis() + record.first.timeToLive.toLong() * 1000L), record.second.domainName)
cachedPtrRecord.replaceOrAdd(newPtrRecord) { it.target == record.second.domainName }
}
aRecords.forEach { aRecord ->
val cachedARecord = _cachedAddressRecords.getOrPut(aRecord.first.name) { mutableListOf() }
val newARecord = CachedDnsAddressRecord(Date(System.currentTimeMillis() + aRecord.first.timeToLive.toLong() * 1000L), aRecord.second.address)
cachedARecord.replaceOrAdd(newARecord) { it.address == newARecord.address }
}
aaaaRecords.forEach { aaaaRecord ->
val cachedAaaaRecord = _cachedAddressRecords.getOrPut(aaaaRecord.first.name) { mutableListOf() }
val newAaaaRecord = CachedDnsAddressRecord(Date(System.currentTimeMillis() + aaaaRecord.first.timeToLive.toLong() * 1000L), aaaaRecord.second.address)
cachedAaaaRecord.replaceOrAdd(newAaaaRecord) { it.address == newAaaaRecord.address }
}
txtRecords.forEach { txtRecord ->
_cachedTxtRecords[txtRecord.first.name] = CachedDnsTxtRecord(Date(System.currentTimeMillis() + txtRecord.first.timeToLive.toLong() * 1000L), txtRecord.second.texts)
}
srvRecords.forEach { srvRecord ->
_cachedSrvRecords[srvRecord.first.name] = CachedDnsSrvRecord(Date(System.currentTimeMillis() + srvRecord.first.timeToLive.toLong() * 1000L), srvRecord.second)
}
currentServices = getCurrentServices()
this._currentServices.clear()
this._currentServices.addAll(currentServices)

View file

@ -12,6 +12,8 @@ import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.receivers.MediaControlReceiver
import com.futo.platformplayer.timestampRegex
import com.futo.platformplayer.views.behavior.NonScrollingTextView
import com.futo.platformplayer.views.behavior.NonScrollingTextView.Companion
import kotlinx.coroutines.runBlocking
class PlatformLinkMovementMethod : LinkMovementMethod {
@ -23,6 +25,7 @@ class PlatformLinkMovementMethod : LinkMovementMethod {
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
val action = event.action;
Logger.i(TAG, "onTouchEvent (action = $action)")
if (action == MotionEvent.ACTION_UP) {
val x = event.x.toInt() - widget.totalPaddingLeft + widget.scrollX;
val y = event.y.toInt() - widget.totalPaddingTop + widget.scrollY;

View file

@ -2,6 +2,8 @@ package com.futo.platformplayer.states
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
@ -20,9 +22,13 @@ import androidx.lifecycle.lifecycleScope
import androidx.work.*
import com.futo.platformplayer.*
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs.Action
import com.futo.platformplayer.UIDialogs.ActionStyle
import com.futo.platformplayer.UIDialogs.Companion.showDialog
import com.futo.platformplayer.activities.CaptchaActivity
import com.futo.platformplayer.activities.IWithResultLauncher
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.activities.SettingsActivity
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.background.BackgroundWorker
@ -419,8 +425,17 @@ class StateApp {
Logger.onLogSubmitted.subscribe {
scopeOrNull?.launch(Dispatchers.Main) {
try {
if (it != null) {
UIDialogs.toast("Uploaded $it", true);
if (!it.isNullOrEmpty()) {
(SettingsActivity.getActivity() ?: contextOrNull)?.let { c ->
val okButtonAction = Action(c.getString(R.string.ok), {}, ActionStyle.PRIMARY)
val copyButtonAction = Action(c.getString(R.string.copy), {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Log id", it)
clipboard.setPrimaryClip(clip)
}, ActionStyle.NONE)
showDialog(c, R.drawable.ic_error, "Uploaded $it", null, null, 0, copyButtonAction, okButtonAction)
}
} else {
UIDialogs.toast("Failed to upload");
}

View file

@ -6,6 +6,8 @@ import android.widget.FrameLayout
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
@ -53,14 +55,30 @@ class VideoListEditorView : FrameLayout {
};
adapterVideos.onRemove.subscribe { v ->
synchronized(_videos) {
val index = _videos.indexOf(v);
if(index >= 0) {
_videos.removeAt(index);
onVideoRemoved.emit(v);
val executeDelete = {
synchronized(_videos) {
val index = _videos.indexOf(v);
if(index >= 0) {
_videos.removeAt(index);
onVideoRemoved.emit(v);
}
adapterVideos.notifyItemRemoved(index);
}
adapterVideos.notifyItemRemoved(index);
}
if (Settings.instance.other.playlistDeleteConfirmation) {
UIDialogs.showConfirmationDialog(context, "Please confirm to delete", action = {
executeDelete()
}, cancelAction = {
}, doNotAskAgainAction = {
Settings.instance.other.playlistDeleteConfirmation = false
Settings.instance.save()
})
} else {
executeDelete()
}
};
adapterVideos.onClick.subscribe(onVideoClicked::emit);

View file

@ -82,6 +82,7 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="confirm">Confirm</string>
<string name="do_not_ask_again">Don\'t ask again</string>
<string name="confirm_delete_playlist">Are you sure you want to delete this playlist?</string>
<string name="confirm_delete_subscription">Are you sure you want to delete this subscription?</string>
<string name="confirm_remove_source">Removing this source will result in some of your subscriptions not being resolved.</string>
@ -418,6 +419,8 @@
<string name="payment">Payment</string>
<string name="payment_status">Payment Status</string>
<string name="bypass_rotation_prevention">Bypass Rotation Prevention</string>
<string name="playlist_delete_confirmation">Playlist Delete Confirmation</string>
<string name="playlist_delete_confirmation_description">Show confirmation dialog when deleting media from a playlist</string>
<string name="enable_polycentric">Enable Polycentric</string>
<string name="can_be_disabled_when_you_are_experiencing_issues">Can be disabled when you are experiencing issues</string>
<string name="bypass_rotation_prevention_description">Allows for rotation on non-video views.\nWARNING: Not designed for it</string>

View file

@ -38,6 +38,8 @@
<data android:host="bitchute.com" />
<data android:host="www.bitchute.com" />
<data android:host="old.bitchute.com" />
<data android:host="open.spotify.com" />
<data android:host="music.youtube.com" />
<data android:pathPrefix="/" />
</intent-filter>
<intent-filter android:autoVerify="true">
@ -67,6 +69,8 @@
<data android:host="bitchute.com" />
<data android:host="www.bitchute.com" />
<data android:host="old.bitchute.com" />
<data android:host="open.spotify.com" />
<data android:host="music.youtube.com" />
</intent-filter>
</activity>
</application>