mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-04 23:30:52 +00:00
stripped down data to only URL and plugin id. removed modal data preview
This commit is contained in:
parent
bf1a6b7d0a
commit
18ccaadc5b
2 changed files with 174 additions and 154 deletions
|
@ -7,7 +7,6 @@ import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.wifi.WifiManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import android.os.StrictMode.VmPolicy
|
import android.os.StrictMode.VmPolicy
|
||||||
|
@ -82,6 +81,7 @@ import com.futo.platformplayer.states.StatePlayer
|
||||||
import com.futo.platformplayer.states.StatePlaylists
|
import com.futo.platformplayer.states.StatePlaylists
|
||||||
import com.futo.platformplayer.states.StateSubscriptions
|
import com.futo.platformplayer.states.StateSubscriptions
|
||||||
import com.futo.platformplayer.stores.FragmentedStorage
|
import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
|
import com.futo.platformplayer.stores.StringStorage
|
||||||
import com.futo.platformplayer.stores.SubscriptionStorage
|
import com.futo.platformplayer.stores.SubscriptionStorage
|
||||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||||
import com.futo.platformplayer.views.ToastView
|
import com.futo.platformplayer.views.ToastView
|
||||||
|
@ -95,6 +95,8 @@ import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
|
@ -103,9 +105,6 @@ import java.lang.reflect.InvocationTargetException
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import java.util.Queue
|
import java.util.Queue
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import org.json.JSONArray
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity, IWithResultLauncher {
|
class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
|
|
||||||
|
@ -260,7 +259,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
setNavigationBarColorAndIcons();
|
setNavigationBarColorAndIcons();
|
||||||
if (Settings.instance.playback.allowVideoToGoUnderCutout)
|
if (Settings.instance.playback.allowVideoToGoUnderCutout)
|
||||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
StatePlatform.instance.updateAvailableClients(this@MainActivity);
|
StatePlatform.instance.updateAvailableClients(this@MainActivity);
|
||||||
|
@ -335,9 +335,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
};
|
};
|
||||||
_fragVideoDetail.onTransitioning.subscribe {
|
_fragVideoDetail.onTransitioning.subscribe {
|
||||||
if (it || _fragVideoDetail.state != VideoDetailFragment.State.MINIMIZED)
|
if (it || _fragVideoDetail.state != VideoDetailFragment.State.MINIMIZED)
|
||||||
_fragContainerOverlay.elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15f, resources.displayMetrics);
|
_fragContainerOverlay.elevation =
|
||||||
|
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15f, resources.displayMetrics);
|
||||||
else
|
else
|
||||||
_fragContainerOverlay.elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, resources.displayMetrics);
|
_fragContainerOverlay.elevation =
|
||||||
|
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, resources.displayMetrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
_fragVideoDetail.onCloseEvent.subscribe {
|
_fragVideoDetail.onCloseEvent.subscribe {
|
||||||
|
@ -357,8 +359,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
if (it) {
|
if (it) {
|
||||||
_buttonIncognito.elevation = 99f;
|
_buttonIncognito.elevation = 99f;
|
||||||
_buttonIncognito.alpha = 1f;
|
_buttonIncognito.alpha = 1f;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
_buttonIncognito.elevation = -99f;
|
_buttonIncognito.elevation = -99f;
|
||||||
_buttonIncognito.alpha = 0f;
|
_buttonIncognito.alpha = 0f;
|
||||||
}
|
}
|
||||||
|
@ -366,14 +367,16 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
_buttonIncognito.setOnClickListener {
|
_buttonIncognito.setOnClickListener {
|
||||||
if (!StateApp.instance.privateMode)
|
if (!StateApp.instance.privateMode)
|
||||||
return@setOnClickListener;
|
return@setOnClickListener;
|
||||||
UIDialogs.showDialog(this, R.drawable.ic_disabled_visible_purple, "Disable Privacy Mode",
|
UIDialogs.showDialog(
|
||||||
|
this, R.drawable.ic_disabled_visible_purple, "Disable Privacy Mode",
|
||||||
"Do you want to disable privacy mode? New videos will be tracked again.", null, 0,
|
"Do you want to disable privacy mode? New videos will be tracked again.", null, 0,
|
||||||
UIDialogs.Action("Cancel", {
|
UIDialogs.Action("Cancel", {
|
||||||
StateApp.instance.setPrivacyMode(true);
|
StateApp.instance.setPrivacyMode(true);
|
||||||
}, UIDialogs.ActionStyle.NONE),
|
}, UIDialogs.ActionStyle.NONE),
|
||||||
UIDialogs.Action("Disable", {
|
UIDialogs.Action("Disable", {
|
||||||
StateApp.instance.setPrivacyMode(false);
|
StateApp.instance.setPrivacyMode(false);
|
||||||
}, UIDialogs.ActionStyle.DANGEROUS));
|
}, UIDialogs.ActionStyle.DANGEROUS)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
_fragVideoDetail.onFullscreenChanged.subscribe {
|
_fragVideoDetail.onFullscreenChanged.subscribe {
|
||||||
Logger.i(TAG, "onFullscreenChanged ${it}");
|
Logger.i(TAG, "onFullscreenChanged ${it}");
|
||||||
|
@ -381,13 +384,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
if (it) {
|
if (it) {
|
||||||
_buttonIncognito.elevation = -99f;
|
_buttonIncognito.elevation = -99f;
|
||||||
_buttonIncognito.alpha = 0f;
|
_buttonIncognito.alpha = 0f;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (StateApp.instance.privateMode) {
|
if (StateApp.instance.privateMode) {
|
||||||
_buttonIncognito.elevation = 99f;
|
_buttonIncognito.elevation = 99f;
|
||||||
_buttonIncognito.alpha = 1f;
|
_buttonIncognito.alpha = 1f;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
_buttonIncognito.elevation = -99f;
|
_buttonIncognito.elevation = -99f;
|
||||||
_buttonIncognito.alpha = 0f;
|
_buttonIncognito.alpha = 0f;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +453,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
fragCurrent = _fragMainHome;
|
fragCurrent = _fragMainHome;
|
||||||
|
|
||||||
val defaultTab = Settings.instance.tabs.mapNotNull {
|
val defaultTab = Settings.instance.tabs.mapNotNull {
|
||||||
val buttonDefinition = MenuBottomBarFragment.buttonDefinitions.firstOrNull { bd -> it.id == bd.id };
|
val buttonDefinition =
|
||||||
|
MenuBottomBarFragment.buttonDefinitions.firstOrNull { bd -> it.id == bd.id };
|
||||||
if (buttonDefinition == null) {
|
if (buttonDefinition == null) {
|
||||||
return@mapNotNull null;
|
return@mapNotNull null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -511,53 +513,56 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
|
|
||||||
//startActivity(Intent(this, TestActivity::class.java));
|
//startActivity(Intent(this, TestActivity::class.java));
|
||||||
|
|
||||||
val sharedPreferencesFirstBoot = getSharedPreferences("GrayjayFirstBoot", Context.MODE_PRIVATE)
|
val sharedPreferences =
|
||||||
val isFirstBoot = sharedPreferencesFirstBoot.getBoolean("IsFirstBoot", true)
|
getSharedPreferences("GrayjayFirstBoot", Context.MODE_PRIVATE)
|
||||||
|
val isFirstBoot = sharedPreferences.getBoolean("IsFirstBoot", true)
|
||||||
if (isFirstBoot) {
|
if (isFirstBoot) {
|
||||||
UIDialogs.showConfirmationDialog(this, getString(R.string.do_you_want_to_see_the_tutorials_you_can_find_them_at_any_time_through_the_more_button), {
|
UIDialogs.showConfirmationDialog(this, getString(R.string.do_you_want_to_see_the_tutorials_you_can_find_them_at_any_time_through_the_more_button), {
|
||||||
navigate(_fragMainTutorial)
|
navigate(_fragMainTutorial)
|
||||||
})
|
})
|
||||||
|
|
||||||
sharedPreferencesFirstBoot.edit().putBoolean("IsFirstBoot", false).apply()
|
sharedPreferences.edit().putBoolean("IsFirstBoot", false).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
val sharedPreferencesSubmitSubscriptions =
|
val submissionStatus = FragmentedStorage.get<StringStorage>("subscriptionSubmissionStatus")
|
||||||
getSharedPreferences("GrayjaySubmitSubscriptions", Context.MODE_PRIVATE)
|
|
||||||
val alreadyViewed = sharedPreferencesSubmitSubscriptions.getBoolean("AlreadyViewed", false)
|
|
||||||
|
|
||||||
@Serializable
|
val numSubscriptions = StateSubscriptions.instance.getSubscriptionCount()
|
||||||
data class CreatorInfo(val pluginId: String, val plugin: String, val id: String, val name: String, val url: String, val description: String, val subscribers: Long)
|
|
||||||
|
|
||||||
val subscriptions = StateSubscriptions.instance.getSubscriptions().map { original ->
|
|
||||||
CreatorInfo(
|
|
||||||
pluginId = original.channel.id.pluginId ?: "",
|
|
||||||
plugin = original.channel.id.platform,
|
|
||||||
id = original.channel.id.value ?: "",
|
|
||||||
name = original.channel.name,
|
|
||||||
url = original.channel.url,
|
|
||||||
description = original.channel.description ?: "",
|
|
||||||
subscribers = original.channel.subscribers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val subscriptionsThreshold = 20
|
val subscriptionsThreshold = 20
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!alreadyViewed
|
submissionStatus.value == ""
|
||||||
&& StateApp.instance.getCurrentNetworkState() != StateApp.NetworkState.DISCONNECTED
|
&& StateApp.instance.getCurrentNetworkState() != StateApp.NetworkState.DISCONNECTED
|
||||||
&& subscriptions.size >= subscriptionsThreshold
|
&& numSubscriptions >= subscriptionsThreshold
|
||||||
) {
|
) {
|
||||||
val json = Json.encodeToString(subscriptions)
|
|
||||||
UIDialogs.showDialog(
|
UIDialogs.showDialog(
|
||||||
this,
|
this,
|
||||||
R.drawable.ic_internet,
|
R.drawable.ic_internet,
|
||||||
getString(R.string.donate_personal_subscriptions_list),
|
getString(R.string.contribute_personal_subscriptions_list),
|
||||||
getString(R.string.donate_personal_subscriptions_list_description),
|
getString(R.string.contribute_personal_subscriptions_list_description),
|
||||||
JSONArray(json).toString(4),
|
null,
|
||||||
0,
|
0,
|
||||||
UIDialogs.Action("Cancel", { }, UIDialogs.ActionStyle.NONE),
|
UIDialogs.Action("Cancel", {
|
||||||
|
submissionStatus.setAndSave("dismissed")
|
||||||
|
}, UIDialogs.ActionStyle.NONE),
|
||||||
UIDialogs.Action("Upload", {
|
UIDialogs.Action("Upload", {
|
||||||
|
submissionStatus.setAndSave("submitted")
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
@Serializable
|
||||||
|
data class CreatorInfo(val pluginId: String, val url: String)
|
||||||
|
|
||||||
|
val subscriptions =
|
||||||
|
StateSubscriptions.instance.getSubscriptions().map { original ->
|
||||||
|
CreatorInfo(
|
||||||
|
pluginId = original.channel.id.pluginId ?: "",
|
||||||
|
url = original.channel.url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val json = Json.encodeToString(subscriptions)
|
||||||
|
|
||||||
val url = "https://data.grayjay.app/donate-subscription-list"
|
val url = "https://data.grayjay.app/donate-subscription-list"
|
||||||
val client = ManagedHttpClient();
|
val client = ManagedHttpClient();
|
||||||
val headers = hashMapOf(
|
val headers = hashMapOf(
|
||||||
|
@ -575,8 +580,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
}
|
}
|
||||||
}, UIDialogs.ActionStyle.PRIMARY)
|
}, UIDialogs.ActionStyle.PRIMARY)
|
||||||
)
|
)
|
||||||
|
|
||||||
sharedPreferencesSubmitSubscriptions.edit().putBoolean("AlreadyViewed", true).apply()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,9 +654,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
|
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
Intent.ACTION_SEND -> {
|
Intent.ACTION_SEND -> {
|
||||||
targetData = intent.getStringExtra(Intent.EXTRA_STREAM) ?: intent.getStringExtra(Intent.EXTRA_TEXT);
|
targetData = intent.getStringExtra(Intent.EXTRA_STREAM)
|
||||||
|
?: intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
Logger.i(TAG, "Share Received: " + targetData);
|
Logger.i(TAG, "Share Received: " + targetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent.ACTION_VIEW -> {
|
Intent.ACTION_VIEW -> {
|
||||||
targetData = intent.dataString
|
targetData = intent.dataString
|
||||||
|
|
||||||
|
@ -661,18 +666,22 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
Logger.i(TAG, "View Received: " + targetData);
|
Logger.i(TAG, "View Received: " + targetData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"VIDEO" -> {
|
"VIDEO" -> {
|
||||||
val url = intent.getStringExtra("VIDEO");
|
val url = intent.getStringExtra("VIDEO");
|
||||||
navigate(_fragVideoDetail, url);
|
navigate(_fragVideoDetail, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
"IMPORT_OPTIONS" -> {
|
"IMPORT_OPTIONS" -> {
|
||||||
UIDialogs.showImportOptionsDialog(this);
|
UIDialogs.showImportOptionsDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
"ACTION" -> {
|
"ACTION" -> {
|
||||||
val action = intent.getStringExtra("ACTION");
|
val action = intent.getStringExtra("ACTION");
|
||||||
StateDeveloper.instance.testState = "TestPlayback";
|
StateDeveloper.instance.testState = "TestPlayback";
|
||||||
StateDeveloper.instance.testPlayback();
|
StateDeveloper.instance.testPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
"TAB" -> {
|
"TAB" -> {
|
||||||
when (intent.getStringExtra("TAB")) {
|
when (intent.getStringExtra("TAB")) {
|
||||||
"Sources" -> {
|
"Sources" -> {
|
||||||
|
@ -704,8 +713,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
handleUrlAll(targetData)
|
handleUrlAll(targetData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (ex: Throwable) {
|
||||||
catch(ex: Throwable) {
|
|
||||||
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_handle_file), ex);
|
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_handle_file), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -715,32 +723,28 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
when (uri.scheme) {
|
when (uri.scheme) {
|
||||||
"grayjay" -> {
|
"grayjay" -> {
|
||||||
if (url.startsWith("grayjay://license/")) {
|
if (url.startsWith("grayjay://license/")) {
|
||||||
if(StatePayment.instance.setPaymentLicenseUrl(url))
|
if (StatePayment.instance.setPaymentLicenseUrl(url)) {
|
||||||
{
|
|
||||||
UIDialogs.showDialogOk(this, R.drawable.ic_check, getString(R.string.your_license_key_has_been_set_an_app_restart_might_be_required));
|
UIDialogs.showDialogOk(this, R.drawable.ic_check, getString(R.string.your_license_key_has_been_set_an_app_restart_might_be_required));
|
||||||
|
|
||||||
if (fragCurrent is BuyFragment)
|
if (fragCurrent is BuyFragment)
|
||||||
closeSegment(fragCurrent);
|
closeSegment(fragCurrent);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
UIDialogs.toast(getString(R.string.invalid_license_format));
|
UIDialogs.toast(getString(R.string.invalid_license_format));
|
||||||
|
|
||||||
}
|
} else if (url.startsWith("grayjay://plugin/")) {
|
||||||
else if(url.startsWith("grayjay://plugin/")) {
|
|
||||||
val intent = Intent(this, AddSourceActivity::class.java).apply {
|
val intent = Intent(this, AddSourceActivity::class.java).apply {
|
||||||
data = Uri.parse(url.substring("grayjay://plugin/".length));
|
data = Uri.parse(url.substring("grayjay://plugin/".length));
|
||||||
};
|
};
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
} else if (url.startsWith("grayjay://video/")) {
|
||||||
else if(url.startsWith("grayjay://video/")) {
|
|
||||||
val videoUrl = url.substring("grayjay://video/".length);
|
val videoUrl = url.substring("grayjay://video/".length);
|
||||||
navigate(_fragVideoDetail, videoUrl);
|
navigate(_fragVideoDetail, videoUrl);
|
||||||
}
|
} else if (url.startsWith("grayjay://channel/")) {
|
||||||
else if(url.startsWith("grayjay://channel/")) {
|
|
||||||
val channelUrl = url.substring("grayjay://channel/".length);
|
val channelUrl = url.substring("grayjay://channel/".length);
|
||||||
navigate(_fragMainChannel, channelUrl);
|
navigate(_fragMainChannel, channelUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"content" -> {
|
"content" -> {
|
||||||
if (!handleContent(url, intent.type)) {
|
if (!handleContent(url, intent.type)) {
|
||||||
UIDialogs.showSingleButtonDialog(
|
UIDialogs.showSingleButtonDialog(
|
||||||
|
@ -751,6 +755,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
{ });
|
{ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"file" -> {
|
"file" -> {
|
||||||
if (!handleFile(url)) {
|
if (!handleFile(url)) {
|
||||||
UIDialogs.showSingleButtonDialog(
|
UIDialogs.showSingleButtonDialog(
|
||||||
|
@ -761,6 +766,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
{ });
|
{ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"polycentric" -> {
|
"polycentric" -> {
|
||||||
if (!handlePolycentric(url)) {
|
if (!handlePolycentric(url)) {
|
||||||
UIDialogs.showSingleButtonDialog(
|
UIDialogs.showSingleButtonDialog(
|
||||||
|
@ -771,6 +777,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
{ });
|
{ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"fcast" -> {
|
"fcast" -> {
|
||||||
if (!handleFCast(url)) {
|
if (!handleFCast(url)) {
|
||||||
UIDialogs.showSingleButtonDialog(
|
UIDialogs.showSingleButtonDialog(
|
||||||
|
@ -781,6 +788,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
{ });
|
{ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (!handleUrl(url)) {
|
if (!handleUrl(url)) {
|
||||||
UIDialogs.showSingleButtonDialog(
|
UIDialogs.showSingleButtonDialog(
|
||||||
|
@ -830,6 +838,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
return@withContext false;
|
return@withContext false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleContent(file: String, mime: String? = null): Boolean {
|
fun handleContent(file: String, mime: String? = null): Boolean {
|
||||||
Logger.i(TAG, "handleContent(url=$file)");
|
Logger.i(TAG, "handleContent(url=$file)");
|
||||||
|
|
||||||
|
@ -840,14 +849,14 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
return handleUnknownJson(recon);
|
return handleUnknownJson(recon);
|
||||||
|
|
||||||
var reconLines = Json.decodeFromString<List<String>>(recon);
|
var reconLines = Json.decodeFromString<List<String>>(recon);
|
||||||
val cacheStr = reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length);
|
val cacheStr =
|
||||||
|
reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length);
|
||||||
reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix
|
reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix
|
||||||
var cache: ImportCache? = null;
|
var cache: ImportCache? = null;
|
||||||
try {
|
try {
|
||||||
if (cacheStr != null)
|
if (cacheStr != null)
|
||||||
cache = Json.decodeFromString(cacheStr);
|
cache = Json.decodeFromString(cacheStr);
|
||||||
}
|
} catch (ex: Throwable) {
|
||||||
catch(ex: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to deserialize cache");
|
Logger.e(TAG, "Failed to deserialize cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -856,16 +865,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
||||||
handleReconstruction(recon, cache);
|
handleReconstruction(recon, cache);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (file.lowercase().endsWith(".zip") || mime == "application/zip") {
|
||||||
else if(file.lowercase().endsWith(".zip") || mime == "application/zip") {
|
|
||||||
StateBackup.importZipBytes(this, lifecycleScope, data);
|
StateBackup.importZipBytes(this, lifecycleScope, data);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (file.lowercase().endsWith(".txt") || mime == "text/plain") {
|
||||||
else if(file.lowercase().endsWith(".txt") || mime == "text/plain") {
|
|
||||||
return handleUnknownText(String(data));
|
return handleUnknownText(String(data));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleFile(file: String): Boolean {
|
fun handleFile(file: String): Boolean {
|
||||||
Logger.i(TAG, "handleFile(url=$file)");
|
Logger.i(TAG, "handleFile(url=$file)");
|
||||||
if (file.lowercase().endsWith(".json")) {
|
if (file.lowercase().endsWith(".json")) {
|
||||||
|
@ -874,14 +882,14 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
return handleUnknownJson(recon);
|
return handleUnknownJson(recon);
|
||||||
|
|
||||||
var reconLines = Json.decodeFromString<List<String>>(recon);
|
var reconLines = Json.decodeFromString<List<String>>(recon);
|
||||||
val cacheStr = reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length);
|
val cacheStr =
|
||||||
|
reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length);
|
||||||
reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix
|
reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix
|
||||||
var cache: ImportCache? = null;
|
var cache: ImportCache? = null;
|
||||||
try {
|
try {
|
||||||
if (cacheStr != null)
|
if (cacheStr != null)
|
||||||
cache = Json.decodeFromString(cacheStr);
|
cache = Json.decodeFromString(cacheStr);
|
||||||
}
|
} catch (ex: Throwable) {
|
||||||
catch(ex: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to deserialize cache");
|
Logger.e(TAG, "Failed to deserialize cache");
|
||||||
}
|
}
|
||||||
recon = reconLines.joinToString("\n");
|
recon = reconLines.joinToString("\n");
|
||||||
|
@ -889,16 +897,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
||||||
handleReconstruction(recon, cache);
|
handleReconstruction(recon, cache);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (file.lowercase().endsWith(".zip")) {
|
||||||
else if(file.lowercase().endsWith(".zip")) {
|
|
||||||
StateBackup.importZipBytes(this, lifecycleScope, readSharedFile(file));
|
StateBackup.importZipBytes(this, lifecycleScope, readSharedFile(file));
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (file.lowercase().endsWith(".txt")) {
|
||||||
else if(file.lowercase().endsWith(".txt")) {
|
|
||||||
return handleUnknownText(String(readSharedFile(file)));
|
return handleUnknownText(String(readSharedFile(file)));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleReconstruction(recon: String, cache: ImportCache? = null) {
|
fun handleReconstruction(recon: String, cache: ImportCache? = null) {
|
||||||
val type = ManagedStore.getReconstructionIdentifier(recon);
|
val type = ManagedStore.getReconstructionIdentifier(recon);
|
||||||
val store: ManagedStore<*> = when (type) {
|
val store: ManagedStore<*> = when (type) {
|
||||||
|
@ -910,7 +917,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
};
|
};
|
||||||
|
|
||||||
val name = when (type) {
|
val name = when (type) {
|
||||||
"Playlist" -> recon.split("\n").filter { !it.startsWith(ManagedStore.RECONSTRUCTION_HEADER_OPERATOR) }.firstOrNull() ?: type;
|
"Playlist" -> recon.split("\n")
|
||||||
|
.filter { !it.startsWith(ManagedStore.RECONSTRUCTION_HEADER_OPERATOR) }
|
||||||
|
.firstOrNull() ?: type;
|
||||||
else -> type
|
else -> type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,13 +938,13 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
navigate(_fragImportSubscriptions, lines);
|
navigate(_fragImportSubscriptions, lines);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} catch (ex: Throwable) {
|
||||||
catch(ex: Throwable) {
|
|
||||||
Logger.e(TAG, ex.message, ex);
|
Logger.e(TAG, ex.message, ex);
|
||||||
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_parse_text_file), ex);
|
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_parse_text_file), ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleUnknownJson(json: String): Boolean {
|
fun handleUnknownJson(json: String): Boolean {
|
||||||
|
|
||||||
val context = this;
|
val context = this;
|
||||||
|
@ -947,8 +956,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
return false;//throw IllegalArgumentException("Invalid NewPipe json structure found");
|
return false;//throw IllegalArgumentException("Invalid NewPipe json structure found");
|
||||||
|
|
||||||
StateBackup.importNewPipeSubs(this, newPipeSubsParsed);
|
StateBackup.importNewPipeSubs(this, newPipeSubsParsed);
|
||||||
}
|
} catch (ex: Exception) {
|
||||||
catch(ex: Exception) {
|
|
||||||
Logger.e(TAG, ex.message, ex);
|
Logger.e(TAG, ex.message, ex);
|
||||||
UIDialogs.showGeneralErrorDialog(context, getString(R.string.failed_to_parse_newpipe_subscriptions), ex);
|
UIDialogs.showGeneralErrorDialog(context, getString(R.string.failed_to_parse_newpipe_subscriptions), ex);
|
||||||
}
|
}
|
||||||
|
@ -1078,8 +1086,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
.replace(R.id.fragment_top_bar, segment.topBar as Fragment);
|
.replace(R.id.fragment_top_bar, segment.topBar as Fragment);
|
||||||
fragCurrent.topBar?.onHide();
|
fragCurrent.topBar?.onHide();
|
||||||
}
|
}
|
||||||
}
|
} else if (fragCurrent.topBar != null)
|
||||||
else if(fragCurrent.topBar != null)
|
|
||||||
transaction.hide(fragCurrent.topBar as Fragment);
|
transaction.hide(fragCurrent.topBar as Fragment);
|
||||||
|
|
||||||
transaction = transaction.replace(R.id.fragment_main, segment);
|
transaction = transaction.replace(R.id.fragment_main, segment);
|
||||||
|
@ -1087,8 +1094,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
if (segment.hasBottomBar) {
|
if (segment.hasBottomBar) {
|
||||||
if (!fragCurrent.hasBottomBar)
|
if (!fragCurrent.hasBottomBar)
|
||||||
transaction = transaction.show(_fragBotBarMenu);
|
transaction = transaction.show(_fragBotBarMenu);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (fragCurrent.hasBottomBar)
|
if (fragCurrent.hasBottomBar)
|
||||||
transaction = transaction.hide(_fragBotBarMenu);
|
transaction = transaction.hide(_fragBotBarMenu);
|
||||||
}
|
}
|
||||||
|
@ -1191,12 +1197,18 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
if (fragCurrent.hasBottomBar)
|
if (fragCurrent.hasBottomBar)
|
||||||
paddingBottom += HEIGHT_MENU_DP;
|
paddingBottom += HEIGHT_MENU_DP;
|
||||||
|
|
||||||
_fragContainerOverlay.setPadding(0,0,0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom - HEIGHT_MENU_DP, resources.displayMetrics).toInt());
|
_fragContainerOverlay.setPadding(
|
||||||
|
0, 0, 0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom - HEIGHT_MENU_DP, resources.displayMetrics)
|
||||||
|
.toInt()
|
||||||
|
);
|
||||||
|
|
||||||
if (_fragVideoDetail.state == VideoDetailFragment.State.MINIMIZED)
|
if (_fragVideoDetail.state == VideoDetailFragment.State.MINIMIZED)
|
||||||
paddingBottom += HEIGHT_VIDEO_MINIMIZED_DP;
|
paddingBottom += HEIGHT_VIDEO_MINIMIZED_DP;
|
||||||
|
|
||||||
_fragContainerMain.setPadding(0,0,0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, resources.displayMetrics).toInt());
|
_fragContainerMain.setPadding(
|
||||||
|
0, 0, 0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, resources.displayMetrics)
|
||||||
|
.toInt()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1212,14 +1224,18 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
ContextCompat.checkSelfPermission(this, notifPermission) == PackageManager.PERMISSION_GRANTED -> {
|
ContextCompat.checkSelfPermission(this, notifPermission) == PackageManager.PERMISSION_GRANTED -> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityCompat.shouldShowRequestPermissionRationale(this, notifPermission) -> {
|
ActivityCompat.shouldShowRequestPermissionRationale(this, notifPermission) -> {
|
||||||
UIDialogs.showDialog(this, R.drawable.ic_notifications, "Notifications Required",
|
UIDialogs.showDialog(
|
||||||
|
this, R.drawable.ic_notifications, "Notifications Required",
|
||||||
reason, null, 0,
|
reason, null, 0,
|
||||||
UIDialogs.Action("Cancel", {}),
|
UIDialogs.Action("Cancel", {}),
|
||||||
UIDialogs.Action("Enable", {
|
UIDialogs.Action("Enable", {
|
||||||
requestPermissionLauncher.launch(notifPermission);
|
requestPermissionLauncher.launch(notifPermission);
|
||||||
}, UIDialogs.ActionStyle.PRIMARY));
|
}, UIDialogs.ActionStyle.PRIMARY)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
requestPermissionLauncher.launch(notifPermission);
|
requestPermissionLauncher.launch(notifPermission);
|
||||||
}
|
}
|
||||||
|
@ -1237,6 +1253,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun launchAppToastJob() {
|
private suspend fun launchAppToastJob() {
|
||||||
Logger.i(TAG, "Starting appToast loop");
|
Logger.i(TAG, "Starting appToast loop");
|
||||||
while (!_toastQueue.isEmpty()) {
|
while (!_toastQueue.isEmpty()) {
|
||||||
|
@ -1269,14 +1286,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
private var resultLauncherMap = mutableMapOf<Int, (ActivityResult) -> Unit>();
|
private var resultLauncherMap = mutableMapOf<Int, (ActivityResult) -> Unit>();
|
||||||
private var requestCode: Int? = -1;
|
private var requestCode: Int? = -1;
|
||||||
private val resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
|
private val resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()) {
|
ActivityResultContracts.StartActivityForResult()
|
||||||
result: ActivityResult ->
|
) { result: ActivityResult ->
|
||||||
val handler = synchronized(resultLauncherMap) {
|
val handler = synchronized(resultLauncherMap) {
|
||||||
resultLauncherMap.remove(requestCode);
|
resultLauncherMap.remove(requestCode);
|
||||||
}
|
}
|
||||||
if (handler != null)
|
if (handler != null)
|
||||||
handler(result);
|
handler(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
override fun launchForResult(intent: Intent, code: Int, handler: (ActivityResult) -> Unit) {
|
override fun launchForResult(intent: Intent, code: Int, handler: (ActivityResult) -> Unit) {
|
||||||
synchronized(resultLauncherMap) {
|
synchronized(resultLauncherMap) {
|
||||||
resultLauncherMap[code] = handler;
|
resultLauncherMap[code] = handler;
|
||||||
|
@ -1295,6 +1313,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
return sourcesIntent;
|
return sourcesIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVideoIntent(context: Context, videoUrl: String): Intent {
|
fun getVideoIntent(context: Context, videoUrl: String): Intent {
|
||||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||||
sourcesIntent.action = "VIDEO";
|
sourcesIntent.action = "VIDEO";
|
||||||
|
@ -1302,6 +1321,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
return sourcesIntent;
|
return sourcesIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getActionIntent(context: Context, action: String): Intent {
|
fun getActionIntent(context: Context, action: String): Intent {
|
||||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||||
sourcesIntent.action = "ACTION";
|
sourcesIntent.action = "ACTION";
|
||||||
|
|
|
@ -803,8 +803,8 @@
|
||||||
<string name="scroll_to_top">Scroll to top</string>
|
<string name="scroll_to_top">Scroll to top</string>
|
||||||
<string name="disable_battery_optimization">Disable Battery Optimization</string>
|
<string name="disable_battery_optimization">Disable Battery Optimization</string>
|
||||||
<string name="click_to_go_to_battery_optimization_settings_disabling_battery_optimization_will_prevent_the_os_from_killing_media_sessions">Click to go to battery optimization settings. Disabling battery optimization will prevent the OS from killing media sessions.</string>
|
<string name="click_to_go_to_battery_optimization_settings_disabling_battery_optimization_will_prevent_the_os_from_killing_media_sessions">Click to go to battery optimization settings. Disabling battery optimization will prevent the OS from killing media sessions.</string>
|
||||||
<string name="donate_personal_subscriptions_list">Donate Personal Subscriptions List</string>
|
<string name="contribute_personal_subscriptions_list">Contribute Personal Subscriptions List</string>
|
||||||
<string name="donate_personal_subscriptions_list_description">\nWould you liked to donate your current creator subscriptions list to Grayjay?\n\nThe data will be handled according to the Grayjay privacy policy. That is the list will be anonymized and stored without any reference to whomever the list of creators belonged to.\n\nThe intention is for Grayjay and FUTO to use these data to build a cross platform creator recommendation system to make it easier to find new creators you might like from within Grayjay.\n\nThe following data will be uploaded:</string>
|
<string name="contribute_personal_subscriptions_list_description">\nWould you liked to contribute your current creator subscriptions list to FUTO?\n\nThe data will be handled according to the Grayjay privacy policy. That is the list will be anonymized and stored without any reference to whomever the list of creators belonged to.\n\nThe intention is for Grayjay and FUTO to use these data to build a cross platform creator recommendation system to make it easier to find new creators you might like from within Grayjay.</string>
|
||||||
<string-array name="home_screen_array">
|
<string-array name="home_screen_array">
|
||||||
<item>Recommendations</item>
|
<item>Recommendations</item>
|
||||||
<item>Subscriptions</item>
|
<item>Subscriptions</item>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue