mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-07 08:39:30 +00:00
Merge branch 'subscription-submission-modal' into 'master'
Subscription submission modal See merge request videostreaming/grayjay!38
This commit is contained in:
commit
f416f197bc
3 changed files with 216 additions and 131 deletions
|
@ -6,6 +6,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.text.Layout
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
|
@ -198,7 +199,6 @@ class UIDialogs {
|
|||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
fun showDialog(context: Context, icon: Int, text: String, textDetails: String? = null, code: String? = null, defaultCloseAction: Int, vararg actions: Action) {
|
||||
val builder = AlertDialog.Builder(context);
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.dialog_multi_button, null);
|
||||
|
@ -216,16 +216,18 @@ class UIDialogs {
|
|||
view.findViewById<TextView>(R.id.dialog_text_details).apply {
|
||||
if (textDetails == null)
|
||||
this.visibility = View.GONE;
|
||||
else
|
||||
else {
|
||||
this.text = textDetails;
|
||||
this.textAlignment = View.TEXT_ALIGNMENT_VIEW_START
|
||||
}
|
||||
};
|
||||
view.findViewById<TextView>(R.id.dialog_text_code).apply {
|
||||
if(code == null)
|
||||
this.visibility = View.GONE;
|
||||
if (code == null) this.visibility = View.GONE;
|
||||
else {
|
||||
this.text = code;
|
||||
this.movementMethod = ScrollingMovementMethod.getInstance();
|
||||
this.visibility = View.VISIBLE;
|
||||
this.textAlignment = View.TEXT_ALIGNMENT_VIEW_START
|
||||
}
|
||||
};
|
||||
view.findViewById<LinearLayout>(R.id.dialog_buttons).apply {
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
|||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Bundle
|
||||
import android.os.StrictMode
|
||||
import android.os.StrictMode.VmPolicy
|
||||
|
@ -33,6 +32,7 @@ import com.futo.platformplayer.BuildConfig
|
|||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.api.http.ManagedHttpClient
|
||||
import com.futo.platformplayer.casting.StateCasting
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.fragment.mainactivity.bottombar.MenuBottomBarFragment
|
||||
|
@ -81,6 +81,7 @@ import com.futo.platformplayer.states.StatePlayer
|
|||
import com.futo.platformplayer.states.StatePlaylists
|
||||
import com.futo.platformplayer.states.StateSubscriptions
|
||||
import com.futo.platformplayer.stores.FragmentedStorage
|
||||
import com.futo.platformplayer.stores.StringStorage
|
||||
import com.futo.platformplayer.stores.SubscriptionStorage
|
||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||
import com.futo.platformplayer.views.ToastView
|
||||
|
@ -88,11 +89,14 @@ import com.futo.polycentric.core.ApiMethods
|
|||
import com.google.gson.JsonParser
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
|
@ -102,7 +106,6 @@ import java.util.LinkedList
|
|||
import java.util.Queue
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||
|
||||
//TODO: Move to dimensions
|
||||
|
@ -256,7 +259,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
setContentView(R.layout.activity_main);
|
||||
setNavigationBarColorAndIcons();
|
||||
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 {
|
||||
StatePlatform.instance.updateAvailableClients(this@MainActivity);
|
||||
|
@ -331,9 +335,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
};
|
||||
_fragVideoDetail.onTransitioning.subscribe {
|
||||
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
|
||||
_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 {
|
||||
|
@ -353,8 +359,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
if (it) {
|
||||
_buttonIncognito.elevation = 99f;
|
||||
_buttonIncognito.alpha = 1f;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_buttonIncognito.elevation = -99f;
|
||||
_buttonIncognito.alpha = 0f;
|
||||
}
|
||||
|
@ -362,14 +367,16 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
_buttonIncognito.setOnClickListener {
|
||||
if (!StateApp.instance.privateMode)
|
||||
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,
|
||||
UIDialogs.Action("Cancel", {
|
||||
StateApp.instance.setPrivacyMode(true);
|
||||
}, UIDialogs.ActionStyle.NONE),
|
||||
UIDialogs.Action("Disable", {
|
||||
StateApp.instance.setPrivacyMode(false);
|
||||
}, UIDialogs.ActionStyle.DANGEROUS));
|
||||
}, UIDialogs.ActionStyle.DANGEROUS)
|
||||
);
|
||||
};
|
||||
_fragVideoDetail.onFullscreenChanged.subscribe {
|
||||
Logger.i(TAG, "onFullscreenChanged ${it}");
|
||||
|
@ -377,13 +384,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
if (it) {
|
||||
_buttonIncognito.elevation = -99f;
|
||||
_buttonIncognito.alpha = 0f;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (StateApp.instance.privateMode) {
|
||||
_buttonIncognito.elevation = 99f;
|
||||
_buttonIncognito.alpha = 1f;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_buttonIncognito.elevation = -99f;
|
||||
_buttonIncognito.alpha = 0f;
|
||||
}
|
||||
|
@ -448,7 +453,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
fragCurrent = _fragMainHome;
|
||||
|
||||
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) {
|
||||
return@mapNotNull null;
|
||||
} else {
|
||||
|
@ -507,7 +513,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
|
||||
//startActivity(Intent(this, TestActivity::class.java));
|
||||
|
||||
val sharedPreferences = getSharedPreferences("GrayjayFirstBoot", Context.MODE_PRIVATE)
|
||||
val sharedPreferences =
|
||||
getSharedPreferences("GrayjayFirstBoot", Context.MODE_PRIVATE)
|
||||
val isFirstBoot = sharedPreferences.getBoolean("IsFirstBoot", true)
|
||||
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), {
|
||||
|
@ -516,6 +523,64 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
|
||||
sharedPreferences.edit().putBoolean("IsFirstBoot", false).apply()
|
||||
}
|
||||
|
||||
val submissionStatus = FragmentedStorage.get<StringStorage>("subscriptionSubmissionStatus")
|
||||
|
||||
val numSubscriptions = StateSubscriptions.instance.getSubscriptionCount()
|
||||
|
||||
val subscriptionsThreshold = 20
|
||||
|
||||
if (
|
||||
submissionStatus.value == ""
|
||||
&& StateApp.instance.getCurrentNetworkState() != StateApp.NetworkState.DISCONNECTED
|
||||
&& numSubscriptions >= subscriptionsThreshold
|
||||
) {
|
||||
|
||||
UIDialogs.showDialog(
|
||||
this,
|
||||
R.drawable.ic_internet,
|
||||
getString(R.string.contribute_personal_subscriptions_list),
|
||||
getString(R.string.contribute_personal_subscriptions_list_description),
|
||||
null,
|
||||
0,
|
||||
UIDialogs.Action("Cancel", {
|
||||
submissionStatus.setAndSave("dismissed")
|
||||
}, UIDialogs.ActionStyle.NONE),
|
||||
UIDialogs.Action("Upload", {
|
||||
submissionStatus.setAndSave("submitted")
|
||||
|
||||
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 client = ManagedHttpClient();
|
||||
val headers = hashMapOf(
|
||||
"Content-Type" to "application/json"
|
||||
)
|
||||
try {
|
||||
val response = client.post(url, json, headers)
|
||||
// if it failed retry one time
|
||||
if (!response.isOk) {
|
||||
client.post(url, json, headers)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.i(TAG, "Failed to submit subscription list.", e)
|
||||
}
|
||||
}
|
||||
}, UIDialogs.ActionStyle.PRIMARY)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -589,9 +654,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
|
||||
when (intent.action) {
|
||||
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);
|
||||
}
|
||||
|
||||
Intent.ACTION_VIEW -> {
|
||||
targetData = intent.dataString
|
||||
|
||||
|
@ -599,18 +666,22 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
Logger.i(TAG, "View Received: " + targetData);
|
||||
}
|
||||
}
|
||||
|
||||
"VIDEO" -> {
|
||||
val url = intent.getStringExtra("VIDEO");
|
||||
navigate(_fragVideoDetail, url);
|
||||
}
|
||||
|
||||
"IMPORT_OPTIONS" -> {
|
||||
UIDialogs.showImportOptionsDialog(this);
|
||||
}
|
||||
|
||||
"ACTION" -> {
|
||||
val action = intent.getStringExtra("ACTION");
|
||||
StateDeveloper.instance.testState = "TestPlayback";
|
||||
StateDeveloper.instance.testPlayback();
|
||||
}
|
||||
|
||||
"TAB" -> {
|
||||
when (intent.getStringExtra("TAB")) {
|
||||
"Sources" -> {
|
||||
|
@ -642,8 +713,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
handleUrlAll(targetData)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
} catch (ex: Throwable) {
|
||||
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_handle_file), ex);
|
||||
}
|
||||
}
|
||||
|
@ -653,32 +723,28 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
when (uri.scheme) {
|
||||
"grayjay" -> {
|
||||
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));
|
||||
|
||||
if (fragCurrent is BuyFragment)
|
||||
closeSegment(fragCurrent);
|
||||
}
|
||||
else
|
||||
} else
|
||||
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 {
|
||||
data = Uri.parse(url.substring("grayjay://plugin/".length));
|
||||
};
|
||||
startActivity(intent);
|
||||
}
|
||||
else if(url.startsWith("grayjay://video/")) {
|
||||
} else if (url.startsWith("grayjay://video/")) {
|
||||
val videoUrl = url.substring("grayjay://video/".length);
|
||||
navigate(_fragVideoDetail, videoUrl);
|
||||
}
|
||||
else if(url.startsWith("grayjay://channel/")) {
|
||||
} else if (url.startsWith("grayjay://channel/")) {
|
||||
val channelUrl = url.substring("grayjay://channel/".length);
|
||||
navigate(_fragMainChannel, channelUrl);
|
||||
}
|
||||
}
|
||||
|
||||
"content" -> {
|
||||
if (!handleContent(url, intent.type)) {
|
||||
UIDialogs.showSingleButtonDialog(
|
||||
|
@ -689,6 +755,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
{ });
|
||||
}
|
||||
}
|
||||
|
||||
"file" -> {
|
||||
if (!handleFile(url)) {
|
||||
UIDialogs.showSingleButtonDialog(
|
||||
|
@ -699,6 +766,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
{ });
|
||||
}
|
||||
}
|
||||
|
||||
"polycentric" -> {
|
||||
if (!handlePolycentric(url)) {
|
||||
UIDialogs.showSingleButtonDialog(
|
||||
|
@ -709,6 +777,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
{ });
|
||||
}
|
||||
}
|
||||
|
||||
"fcast" -> {
|
||||
if (!handleFCast(url)) {
|
||||
UIDialogs.showSingleButtonDialog(
|
||||
|
@ -719,6 +788,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
{ });
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (!handleUrl(url)) {
|
||||
UIDialogs.showSingleButtonDialog(
|
||||
|
@ -768,6 +838,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
return@withContext false;
|
||||
}
|
||||
}
|
||||
|
||||
fun handleContent(file: String, mime: String? = null): Boolean {
|
||||
Logger.i(TAG, "handleContent(url=$file)");
|
||||
|
||||
|
@ -778,14 +849,14 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
return handleUnknownJson(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
|
||||
var cache: ImportCache? = null;
|
||||
try {
|
||||
if (cacheStr != null)
|
||||
cache = Json.decodeFromString(cacheStr);
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
} catch (ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to deserialize cache");
|
||||
}
|
||||
|
||||
|
@ -794,16 +865,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
||||
handleReconstruction(recon, cache);
|
||||
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);
|
||||
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 false;
|
||||
}
|
||||
|
||||
fun handleFile(file: String): Boolean {
|
||||
Logger.i(TAG, "handleFile(url=$file)");
|
||||
if (file.lowercase().endsWith(".json")) {
|
||||
|
@ -812,14 +882,14 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
return handleUnknownJson(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
|
||||
var cache: ImportCache? = null;
|
||||
try {
|
||||
if (cacheStr != null)
|
||||
cache = Json.decodeFromString(cacheStr);
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
} catch (ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to deserialize cache");
|
||||
}
|
||||
recon = reconLines.joinToString("\n");
|
||||
|
@ -827,16 +897,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
|
||||
handleReconstruction(recon, cache);
|
||||
return true;
|
||||
}
|
||||
else if(file.lowercase().endsWith(".zip")) {
|
||||
} else if (file.lowercase().endsWith(".zip")) {
|
||||
StateBackup.importZipBytes(this, lifecycleScope, readSharedFile(file));
|
||||
return true;
|
||||
}
|
||||
else if(file.lowercase().endsWith(".txt")) {
|
||||
} else if (file.lowercase().endsWith(".txt")) {
|
||||
return handleUnknownText(String(readSharedFile(file)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fun handleReconstruction(recon: String, cache: ImportCache? = null) {
|
||||
val type = ManagedStore.getReconstructionIdentifier(recon);
|
||||
val store: ManagedStore<*> = when (type) {
|
||||
|
@ -848,7 +917,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -867,13 +938,13 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
navigate(_fragImportSubscriptions, lines);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
} catch (ex: Throwable) {
|
||||
Logger.e(TAG, ex.message, ex);
|
||||
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_parse_text_file), ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fun handleUnknownJson(json: String): Boolean {
|
||||
|
||||
val context = this;
|
||||
|
@ -885,8 +956,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
return false;//throw IllegalArgumentException("Invalid NewPipe json structure found");
|
||||
|
||||
StateBackup.importNewPipeSubs(this, newPipeSubsParsed);
|
||||
}
|
||||
catch(ex: Exception) {
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(TAG, ex.message, ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, getString(R.string.failed_to_parse_newpipe_subscriptions), ex);
|
||||
}
|
||||
|
@ -1005,7 +1075,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
fragCurrent.onHide();
|
||||
|
||||
if (segment.isMainView) {
|
||||
|
@ -1017,8 +1086,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
.replace(R.id.fragment_top_bar, segment.topBar as Fragment);
|
||||
fragCurrent.topBar?.onHide();
|
||||
}
|
||||
}
|
||||
else if(fragCurrent.topBar != null)
|
||||
} else if (fragCurrent.topBar != null)
|
||||
transaction.hide(fragCurrent.topBar as Fragment);
|
||||
|
||||
transaction = transaction.replace(R.id.fragment_main, segment);
|
||||
|
@ -1026,8 +1094,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
if (segment.hasBottomBar) {
|
||||
if (!fragCurrent.hasBottomBar)
|
||||
transaction = transaction.show(_fragBotBarMenu);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (fragCurrent.hasBottomBar)
|
||||
transaction = transaction.hide(_fragBotBarMenu);
|
||||
}
|
||||
|
@ -1130,12 +1197,18 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
if (fragCurrent.hasBottomBar)
|
||||
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)
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1151,14 +1224,18 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
ContextCompat.checkSelfPermission(this, notifPermission) == PackageManager.PERMISSION_GRANTED -> {
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
UIDialogs.Action("Cancel", {}),
|
||||
UIDialogs.Action("Enable", {
|
||||
requestPermissionLauncher.launch(notifPermission);
|
||||
}, UIDialogs.ActionStyle.PRIMARY));
|
||||
}, UIDialogs.ActionStyle.PRIMARY)
|
||||
);
|
||||
}
|
||||
|
||||
else -> {
|
||||
requestPermissionLauncher.launch(notifPermission);
|
||||
}
|
||||
|
@ -1176,6 +1253,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun launchAppToastJob() {
|
||||
Logger.i(TAG, "Starting appToast loop");
|
||||
while (!_toastQueue.isEmpty()) {
|
||||
|
@ -1208,14 +1286,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
private var resultLauncherMap = mutableMapOf<Int, (ActivityResult) -> Unit>();
|
||||
private var requestCode: Int? = -1;
|
||||
private val resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()) {
|
||||
result: ActivityResult ->
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result: ActivityResult ->
|
||||
val handler = synchronized(resultLauncherMap) {
|
||||
resultLauncherMap.remove(requestCode);
|
||||
}
|
||||
if (handler != null)
|
||||
handler(result);
|
||||
};
|
||||
|
||||
override fun launchForResult(intent: Intent, code: Int, handler: (ActivityResult) -> Unit) {
|
||||
synchronized(resultLauncherMap) {
|
||||
resultLauncherMap[code] = handler;
|
||||
|
@ -1234,6 +1313,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
return sourcesIntent;
|
||||
}
|
||||
|
||||
fun getVideoIntent(context: Context, videoUrl: String): Intent {
|
||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||
sourcesIntent.action = "VIDEO";
|
||||
|
@ -1241,6 +1321,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
return sourcesIntent;
|
||||
}
|
||||
|
||||
fun getActionIntent(context: Context, action: String): Intent {
|
||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||
sourcesIntent.action = "ACTION";
|
||||
|
|
|
@ -810,6 +810,8 @@
|
|||
<string name="scroll_to_top">Scroll to top</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="contribute_personal_subscriptions_list">Contribute Personal Subscriptions List</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 name="cd_cast_button">Cast button</string>
|
||||
<string name="cd_incognito_button">Incognito button</string>
|
||||
<string name="cd_creator_thumbnail">Creator thumbnail</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue