mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 13:02:39 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd95311920 | |||
| 6da5c11731 | |||
| 4e58231308 | |||
| ef0ecf249a | |||
| 4981617f7a | |||
| 2070bc7007 |
@@ -412,15 +412,13 @@ class Settings : FragmentedStorageFileJson() {
|
||||
var preferredPreviewQuality: Int = 5;
|
||||
fun getPreferredPreviewQualityPixelCount(): Int = preferedQualityToPixels(preferredPreviewQuality);
|
||||
|
||||
|
||||
@FormField(R.string.simplify_sources, FieldForm.TOGGLE, R.string.simplify_sources_description, 4)
|
||||
var simplifySources: Boolean = true;
|
||||
|
||||
@FormField(R.string.auto_rotate, FieldForm.DROPDOWN, -1, 5)
|
||||
@DropdownFieldOptionsId(R.array.system_enabled_disabled_array)
|
||||
var autoRotate: Int = 2;
|
||||
@FormField(R.string.force_allow_full_screen_rotation, FieldForm.TOGGLE, R.string.force_allow_full_screen_rotation_description, 5)
|
||||
var forceAllowFullScreenRotation: Boolean = false
|
||||
|
||||
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 7)
|
||||
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 6)
|
||||
@DropdownFieldOptionsId(R.array.player_background_behavior)
|
||||
var backgroundPlay: Int = 2;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class BuyFragment : MainFragment() {
|
||||
try {
|
||||
val currencies = StatePayment.instance.getAvailableCurrencies("grayjay");
|
||||
val prices = StatePayment.instance.getAvailableCurrencyPrices("grayjay");
|
||||
val country = StatePayment.instance.getPaymentCountryFromIP()?.let { c -> PaymentConfigurations.COUNTRIES.find { it.id.equals(c, ignoreCase = true) } };
|
||||
val country = StatePayment.instance.getPaymentCountryFromIP(true)?.let { c -> PaymentConfigurations.COUNTRIES.find { it.id.equals(c, ignoreCase = true) } };
|
||||
val currency = country?.let { c -> PaymentConfigurations.CURRENCIES.find { it.id == c.defaultCurrencyId && (currencies.contains(it.id)) } };
|
||||
|
||||
if(currency != null && prices.containsKey(currency.id)) {
|
||||
|
||||
+9
-22
@@ -143,7 +143,6 @@ class VideoDetailFragment : MainFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
fun updateOrientation() {
|
||||
val a = activity ?: return
|
||||
val isFullScreenPortraitAllowed = Settings.instance.playback.fullscreenPortrait
|
||||
@@ -156,7 +155,11 @@ class VideoDetailFragment : MainFragment {
|
||||
|
||||
// For small windows if the device isn't landscape right now and full screen portrait isn't allowed then we should force landscape
|
||||
if (isSmallWindow && isFullscreen && !isFullScreenPortraitAllowed && resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT && !rotationLock && isLandscapeVideo) {
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
if(Settings.instance.playback.forceAllowFullScreenRotation){
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
}else{
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
}
|
||||
}
|
||||
// For small windows if the device isn't in a portrait orientation and we're in the maximized state then we should force portrait
|
||||
else if (isSmallWindow && !isMinimizingFromFullScreen && !isFullscreen && state == State.MAXIMIZED && resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
@@ -164,26 +167,10 @@ class VideoDetailFragment : MainFragment {
|
||||
} else if (rotationLock) {
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
} else {
|
||||
when (Settings.instance.playback.autoRotate) {
|
||||
0 -> {
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
}
|
||||
|
||||
1 -> {
|
||||
a.requestedOrientation = if (isReversePortraitAllowed) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_SENSOR
|
||||
}
|
||||
}
|
||||
|
||||
2 -> {
|
||||
a.requestedOrientation = if (isReversePortraitAllowed) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
a.requestedOrientation = if (isReversePortraitAllowed) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,21 +55,25 @@ class ServiceRecordAggregator {
|
||||
if (_cts != null) throw Exception("Already started.")
|
||||
|
||||
_cts = CoroutineScope(Dispatchers.Default).launch {
|
||||
while (isActive) {
|
||||
val now = Date()
|
||||
synchronized(_currentServices) {
|
||||
_cachedAddressRecords.forEach { it.value.removeAll { record -> now.after(record.expirationTime) } }
|
||||
_cachedTxtRecords.entries.removeIf { now.after(it.value.expirationTime) }
|
||||
_cachedSrvRecords.entries.removeIf { now.after(it.value.expirationTime) }
|
||||
_cachedPtrRecords.forEach { it.value.removeAll { record -> now.after(record.expirationTime) } }
|
||||
try {
|
||||
while (isActive) {
|
||||
val now = Date()
|
||||
synchronized(_currentServices) {
|
||||
_cachedAddressRecords.forEach { it.value.removeAll { record -> now.after(record.expirationTime) } }
|
||||
_cachedTxtRecords.entries.removeIf { now.after(it.value.expirationTime) }
|
||||
_cachedSrvRecords.entries.removeIf { now.after(it.value.expirationTime) }
|
||||
_cachedPtrRecords.forEach { it.value.removeAll { record -> now.after(record.expirationTime) } }
|
||||
|
||||
val newServices = getCurrentServices()
|
||||
_currentServices.clear()
|
||||
_currentServices.addAll(newServices)
|
||||
val newServices = getCurrentServices()
|
||||
_currentServices.clear()
|
||||
_currentServices.addAll(newServices)
|
||||
}
|
||||
|
||||
onServicesUpdated?.invoke(_currentServices.toList())
|
||||
delay(5000)
|
||||
}
|
||||
|
||||
onServicesUpdated?.invoke(_currentServices.toList())
|
||||
delay(5000)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Unexpected failure in MDNS loop", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,6 +87,7 @@ class ServiceRecordAggregator {
|
||||
}
|
||||
|
||||
fun add(packet: DnsPacket) {
|
||||
val currentServices: List<DnsService>
|
||||
val dnsResourceRecords = packet.answers + packet.additionals + packet.authorities
|
||||
val txtRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.TXT.value.toInt() }.map { it to it.getDataReader().readTXTRecord() }
|
||||
val aRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.A.value.toInt() }.map { it to it.getDataReader().readARecord() }
|
||||
@@ -99,35 +104,33 @@ class ServiceRecordAggregator {
|
||||
aaaaRecords.forEach { builder.appendLine("AAAA ${it.first.name} ${it.first.type} ${it.first.clazz} TTL ${it.first.timeToLive}: ${it.second.address}") }
|
||||
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)
|
||||
|
||||
@@ -59,7 +59,7 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
|
||||
if (linkPressed && pressedLinks != null) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(widget, event)) {
|
||||
runBlocking {
|
||||
for (link in pressedLinks!!) {
|
||||
Logger.i(TAG) { "Link clicked '${link.url}'." }
|
||||
@@ -101,7 +101,7 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
|
||||
}
|
||||
}
|
||||
|
||||
return super.onTouchEvent(widget, buffer, event)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun findLinksAtTouchPosition(widget: TextView, buffer: Spannable, event: MotionEvent): Array<URLSpan> {
|
||||
@@ -114,6 +114,10 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
|
||||
return buffer.getSpans(off, off, URLSpan::class.java)
|
||||
}
|
||||
|
||||
private fun isTouchInside(widget: TextView, event: MotionEvent): Boolean {
|
||||
return event.x >= 0 && event.x <= widget.width && event.y >= 0 && event.y <= widget.height
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "PlatformLinkMovementMethod"
|
||||
}
|
||||
|
||||
@@ -160,10 +160,6 @@ class StateApp {
|
||||
private var _cacheDirectory: File? = null;
|
||||
private var _persistentDirectory: File? = null;
|
||||
|
||||
|
||||
//AutoRotate
|
||||
var systemAutoRotate: Boolean = false;
|
||||
|
||||
//Network
|
||||
private var _lastMeteredState: Boolean = false;
|
||||
private var _connectivityManager: ConnectivityManager? = null;
|
||||
@@ -201,17 +197,6 @@ class StateApp {
|
||||
return File(_persistentDirectory, name);
|
||||
}
|
||||
|
||||
fun getCurrentSystemAutoRotate(): Boolean {
|
||||
_context?.let {
|
||||
systemAutoRotate = android.provider.Settings.System.getInt(
|
||||
it.contentResolver,
|
||||
android.provider.Settings.System.ACCELEROMETER_ROTATION, 0
|
||||
) == 1;
|
||||
};
|
||||
return systemAutoRotate;
|
||||
}
|
||||
|
||||
|
||||
fun isCurrentMetered(): Boolean {
|
||||
ensureConnectivityManager();
|
||||
return _connectivityManager?.isActiveNetworkMetered ?: throw IllegalStateException("Connectivity manager not available");
|
||||
@@ -312,9 +297,6 @@ class StateApp {
|
||||
fun setGlobalContext(context: Context, coroutineScope: CoroutineScope? = null) {
|
||||
_context = context;
|
||||
_scope = coroutineScope
|
||||
|
||||
//System checks
|
||||
systemAutoRotate = getCurrentSystemAutoRotate();
|
||||
}
|
||||
|
||||
fun initializeFiles(force: Boolean = false) {
|
||||
|
||||
@@ -76,7 +76,7 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
|
||||
if (linkPressed && _lastTouchedLinks != null) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(event)) {
|
||||
runBlocking {
|
||||
for (link in _lastTouchedLinks!!) {
|
||||
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." }
|
||||
@@ -119,7 +119,11 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
|
||||
}
|
||||
}
|
||||
|
||||
return super.onTouchEvent(event)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isTouchInside(event: MotionEvent): Boolean {
|
||||
return event.x >= 0 && event.x <= width && event.y >= 0 && event.y <= height
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -813,17 +813,12 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||
}
|
||||
|
||||
fun updateRotateLock() {
|
||||
if(Settings.instance.playback.autoRotate == 0) {
|
||||
_control_rotate_lock.visibility = View.GONE;
|
||||
_control_rotate_lock_fullscreen.visibility = View.GONE;
|
||||
}
|
||||
else {
|
||||
_control_rotate_lock.visibility = View.VISIBLE;
|
||||
_control_rotate_lock_fullscreen.visibility = View.VISIBLE;
|
||||
}
|
||||
_control_rotate_lock.visibility = View.VISIBLE;
|
||||
_control_rotate_lock_fullscreen.visibility = View.VISIBLE;
|
||||
|
||||
if(StatePlayer.instance.rotationLock) {
|
||||
_control_rotate_lock_fullscreen.setImageResource(R.drawable.ic_screen_rotation);
|
||||
_control_rotate_lock.setImageResource(R.drawable.ic_screen_rotation);
|
||||
_control_rotate_lock_fullscreen.setImageResource(R.drawable.ic_screen_lock_rotation_active);
|
||||
_control_rotate_lock.setImageResource(R.drawable.ic_screen_lock_rotation_active);
|
||||
}
|
||||
else {
|
||||
_control_rotate_lock_fullscreen.setImageResource(R.drawable.ic_screen_lock_rotation);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="@color/colorPrimary"
|
||||
android:pathData="M35.25,23.3 L36.4,22.2 38.6,24.45Q39.5,25.3 39.5,26.55Q39.5,27.8 38.6,28.65L32.5,34.75Q31.6,35.6 30.375,35.6Q29.15,35.6 28.3,34.75L13.8,20.25Q12.95,19.4 12.95,18.15Q12.95,16.9 13.8,16.1L19.95,9.95Q20.8,9.1 22.05,9.1Q23.3,9.1 24.1,9.95L26.45,12.25L25.3,13.35L22.9,10.95Q22.55,10.6 22.025,10.6Q21.5,10.6 21.15,10.95L14.85,17.25Q14.5,17.6 14.5,18.15Q14.5,18.7 14.85,19.05L29.5,33.75Q29.85,34.1 30.4,34.1Q30.95,34.1 31.25,33.75L37.6,27.4Q37.95,27.05 37.95,26.525Q37.95,26 37.6,25.65ZM26.15,44.45Q21.6,44.45 17.6,42.725Q13.6,41 10.625,38.025Q7.65,35.05 5.925,31.025Q4.2,27 4.2,22.5H5.75Q5.75,26.65 7.325,30.35Q8.9,34.05 11.65,36.825Q14.4,39.6 18.125,41.2Q21.85,42.8 26,42.85L18.55,35.35L19.65,34.25L29.5,44.1Q28.6,44.25 27.8,44.35Q27,44.45 26.15,44.45ZM32.4,18Q31.7,18 31.1,17.4Q30.5,16.8 30.5,16.1V10.85Q30.5,10.15 31.1,9.525Q31.7,8.9 32.4,8.9H32.55V6.85Q32.55,5.4 33.575,4.4Q34.6,3.4 36.05,3.4Q37.55,3.4 38.55,4.4Q39.55,5.4 39.55,6.85V8.9H39.75Q40.45,8.9 41,9.525Q41.55,10.15 41.55,10.85V16.1Q41.55,16.8 40.975,17.4Q40.4,18 39.65,18ZM34.05,8.9H38.05V6.85Q38.05,6 37.475,5.425Q36.9,4.85 36.05,4.85Q35.2,4.85 34.625,5.425Q34.05,6 34.05,6.85ZM26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Q26.25,22.35 26.25,22.35Z"/>
|
||||
</vector>
|
||||
@@ -287,10 +287,10 @@
|
||||
<string name="planned_content_notifications_description">Schedules discovered planned content as notifications, resulting in more accurate notifications for this content.</string>
|
||||
<string name="attempt_to_utilize_byte_ranges">Attempt to utilize byte ranges</string>
|
||||
<string name="auto_update">Auto Update</string>
|
||||
<string name="auto_rotate">Auto-Rotate</string>
|
||||
<string name="force_allow_full_screen_rotation">Force Allow Full Screen Rotation</string>
|
||||
<string name="force_allow_full_screen_rotation_description">Allow auto-rotation between the two landscape orientations even when you disable auto-rotate at the system level.</string>
|
||||
<string name="simplify_sources">Simplify sources</string>
|
||||
<string name="simplify_sources_description">Deduplicate sources by resolution so that only more relevant sources are visible.</string>
|
||||
<string name="auto_rotate_dead_zone">Auto-Rotate Dead Zone</string>
|
||||
<string name="automatic_backup">Automatic Backup</string>
|
||||
<string name="background_behavior">Background Behavior</string>
|
||||
<string name="background_update">Background Update</string>
|
||||
@@ -928,17 +928,6 @@
|
||||
<item>On Startup</item>
|
||||
<item>Never</item>
|
||||
</string-array>
|
||||
<string-array name="system_enabled_disabled_array">
|
||||
<item>Disabled</item>
|
||||
<item>Enabled</item>
|
||||
<item>Same as System</item>
|
||||
</string-array>
|
||||
<string-array name="auto_rotate_dead_zone" translatable="false">
|
||||
<item>0</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>20</item>
|
||||
</string-array>
|
||||
<string-array name="enabled_disabled_array">
|
||||
<item>Disabled</item>
|
||||
<item>Enabled</item>
|
||||
|
||||
+1
-1
Submodule dep/futopay updated: c3f532c660...829baef9f0
Reference in New Issue
Block a user