mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-29 13:00:21 +02:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
9075a2599c
@ -23,6 +23,7 @@ import com.futo.platformplayer.views.fields.FormField
|
|||||||
import com.futo.platformplayer.views.fields.FieldForm
|
import com.futo.platformplayer.views.fields.FieldForm
|
||||||
import com.futo.platformplayer.views.fields.FormFieldButton
|
import com.futo.platformplayer.views.fields.FormFieldButton
|
||||||
import com.futo.platformplayer.views.fields.FormFieldWarning
|
import com.futo.platformplayer.views.fields.FormFieldWarning
|
||||||
|
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -44,7 +45,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
@Transient
|
@Transient
|
||||||
val onTabsChanged = Event0();
|
val onTabsChanged = Event0();
|
||||||
|
|
||||||
@FormField(R.string.manage_polycentric_identity, FieldForm.BUTTON, R.string.manage_your_polycentric_identity, -5)
|
@FormField(R.string.manage_polycentric_identity, FieldForm.BUTTON, R.string.manage_your_polycentric_identity, -6)
|
||||||
@FormFieldButton(R.drawable.ic_person)
|
@FormFieldButton(R.drawable.ic_person)
|
||||||
fun managePolycentricIdentity() {
|
fun managePolycentricIdentity() {
|
||||||
SettingsActivity.getActivity()?.let {
|
SettingsActivity.getActivity()?.let {
|
||||||
@ -60,7 +61,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FormField(R.string.show_faq, FieldForm.BUTTON, R.string.get_answers_to_common_questions, -4)
|
@FormField(R.string.show_faq, FieldForm.BUTTON, R.string.get_answers_to_common_questions, -5)
|
||||||
@FormFieldButton(R.drawable.ic_quiz)
|
@FormFieldButton(R.drawable.ic_quiz)
|
||||||
fun openFAQ() {
|
fun openFAQ() {
|
||||||
try {
|
try {
|
||||||
@ -70,7 +71,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
//Ignored
|
//Ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@FormField(R.string.show_issues, FieldForm.BUTTON, R.string.a_list_of_user_reported_and_self_reported_issues, -3)
|
@FormField(R.string.show_issues, FieldForm.BUTTON, R.string.a_list_of_user_reported_and_self_reported_issues, -4)
|
||||||
@FormFieldButton(R.drawable.ic_data_alert)
|
@FormFieldButton(R.drawable.ic_data_alert)
|
||||||
fun openIssues() {
|
fun openIssues() {
|
||||||
try {
|
try {
|
||||||
@ -102,7 +103,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
@FormField(R.string.manage_tabs, FieldForm.BUTTON, R.string.change_tabs_visible_on_the_home_screen, -2)
|
@FormField(R.string.manage_tabs, FieldForm.BUTTON, R.string.change_tabs_visible_on_the_home_screen, -3)
|
||||||
@FormFieldButton(R.drawable.ic_tabs)
|
@FormFieldButton(R.drawable.ic_tabs)
|
||||||
fun manageTabs() {
|
fun manageTabs() {
|
||||||
try {
|
try {
|
||||||
@ -114,6 +115,17 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@FormField(R.string.import_data, FieldForm.BUTTON, R.string.import_data_description, -2)
|
||||||
|
@FormFieldButton(R.drawable.ic_move_up)
|
||||||
|
fun import() {
|
||||||
|
val act = SettingsActivity.getActivity() ?: return;
|
||||||
|
val intent = MainActivity.getImportOptionsIntent(act);
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||||
|
act.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
@FormField(R.string.link_handling, FieldForm.BUTTON, R.string.allow_grayjay_to_handle_links, -1)
|
@FormField(R.string.link_handling, FieldForm.BUTTON, R.string.allow_grayjay_to_handle_links, -1)
|
||||||
@FormFieldButton(R.drawable.ic_link)
|
@FormFieldButton(R.drawable.ic_link)
|
||||||
fun manageLinks() {
|
fun manageLinks() {
|
||||||
@ -405,6 +417,9 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
|
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
|
||||||
@DropdownFieldOptionsId(R.array.comment_sections)
|
@DropdownFieldOptionsId(R.array.comment_sections)
|
||||||
var defaultCommentSection: Int = 0;
|
var defaultCommentSection: Int = 0;
|
||||||
|
|
||||||
|
@FormField(R.string.bad_reputation_comments_fading, FieldForm.TOGGLE, R.string.bad_reputation_comments_fading_description, 0)
|
||||||
|
var badReputationCommentsFading: Boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FormField(R.string.downloads, "group", R.string.configure_downloading_of_videos, 7)
|
@FormField(R.string.downloads, "group", R.string.configure_downloading_of_videos, 7)
|
||||||
@ -712,25 +727,16 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
|
|
||||||
@FormField(R.string.export_data, FieldForm.BUTTON, R.string.creates_a_zip_file_with_your_data_which_can_be_imported_by_opening_it_with_grayjay, 3)
|
@FormField(R.string.export_data, FieldForm.BUTTON, R.string.creates_a_zip_file_with_your_data_which_can_be_imported_by_opening_it_with_grayjay, 3)
|
||||||
fun export() {
|
fun export() {
|
||||||
StateBackup.startExternalBackup();
|
val activity = SettingsActivity.getActivity() ?: return;
|
||||||
|
UISlideOverlays.showOverlay(activity.overlay, "Select export type", null, {},
|
||||||
|
SlideUpMenuItem(activity, R.drawable.ic_share, "Share", "", null, {
|
||||||
|
StateBackup.shareExternalBackup();
|
||||||
|
}),
|
||||||
|
SlideUpMenuItem(activity, R.drawable.ic_download, "File", "", null, {
|
||||||
|
StateBackup.saveExternalBackup(activity);
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@FormField(R.string.import_data, FieldForm.BUTTON, R.string.import_data_description, 4)
|
|
||||||
fun import() {
|
|
||||||
val act = SettingsActivity.getActivity() ?: return;
|
|
||||||
StateApp.instance.requestFileReadAccess(act, null) {
|
|
||||||
if(it != null && it.exists()) {
|
|
||||||
val name = it.name;
|
|
||||||
val contents = it.readBytes(act);
|
|
||||||
if(contents != null) {
|
|
||||||
if(name != null && name.endsWith(".zip", true))
|
|
||||||
StateBackup.importZipBytes(act, act.lifecycleScope, contents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FormField(R.string.payment, FieldForm.GROUP, -1, 17)
|
@FormField(R.string.payment, FieldForm.GROUP, -1, 17)
|
||||||
|
@ -13,6 +13,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.futo.platformplayer.activities.MainActivity
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
import com.futo.platformplayer.casting.StateCasting
|
import com.futo.platformplayer.casting.StateCasting
|
||||||
import com.futo.platformplayer.dialogs.*
|
import com.futo.platformplayer.dialogs.*
|
||||||
@ -189,8 +190,10 @@ class UIDialogs {
|
|||||||
view.findViewById<TextView>(R.id.dialog_text_code).apply {
|
view.findViewById<TextView>(R.id.dialog_text_code).apply {
|
||||||
if(code == null)
|
if(code == null)
|
||||||
this.visibility = View.GONE;
|
this.visibility = View.GONE;
|
||||||
else
|
else {
|
||||||
this.text = code;
|
this.text = code;
|
||||||
|
this.visibility = View.VISIBLE;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
view.findViewById<LinearLayout>(R.id.dialog_buttons).apply {
|
view.findViewById<LinearLayout>(R.id.dialog_buttons).apply {
|
||||||
val buttons = actions.map<Action, TextView> { act ->
|
val buttons = actions.map<Action, TextView> { act ->
|
||||||
@ -326,6 +329,12 @@ class UIDialogs {
|
|||||||
dialog.setOnDismissListener { registerDialogClosed(dialog) };
|
dialog.setOnDismissListener { registerDialogClosed(dialog) };
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
fun showImportOptionsDialog(context: MainActivity) {
|
||||||
|
val dialog = ImportOptionsDialog(context);
|
||||||
|
registerDialogOpened(dialog);
|
||||||
|
dialog.setOnDismissListener { registerDialogClosed(dialog) };
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun showCastingDialog(context: Context) {
|
fun showCastingDialog(context: Context) {
|
||||||
|
@ -1,30 +1,21 @@
|
|||||||
package com.futo.platformplayer
|
package com.futo.platformplayer
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.graphics.Color
|
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageButton
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import com.futo.platformplayer.api.http.ManagedHttpClient
|
import com.futo.platformplayer.api.http.ManagedHttpClient
|
||||||
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
|
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantAudioUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantAudioUrlSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantSubtitleUrlSource
|
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantVideoUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantVideoUrlSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.SubtitleRawSource
|
|
||||||
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
|
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
|
||||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
||||||
import com.futo.platformplayer.casting.StateCasting
|
|
||||||
import com.futo.platformplayer.downloads.VideoLocal
|
import com.futo.platformplayer.downloads.VideoLocal
|
||||||
import com.futo.platformplayer.helpers.VideoHelper
|
import com.futo.platformplayer.helpers.VideoHelper
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
@ -40,12 +31,10 @@ import com.futo.platformplayer.views.pills.RoundButton
|
|||||||
import com.futo.platformplayer.views.pills.RoundButtonGroup
|
import com.futo.platformplayer.views.pills.RoundButtonGroup
|
||||||
import com.futo.platformplayer.views.overlays.slideup.*
|
import com.futo.platformplayer.views.overlays.slideup.*
|
||||||
import com.futo.platformplayer.views.video.FutoVideoPlayerBase
|
import com.futo.platformplayer.views.video.FutoVideoPlayerBase
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.internal.notifyAll
|
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
class UISlideOverlays {
|
class UISlideOverlays {
|
||||||
|
@ -515,6 +515,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||||||
val url = intent.getStringExtra("VIDEO");
|
val url = intent.getStringExtra("VIDEO");
|
||||||
navigate(_fragVideoDetail, url);
|
navigate(_fragVideoDetail, url);
|
||||||
}
|
}
|
||||||
|
"IMPORT_OPTIONS" -> {
|
||||||
|
UIDialogs.showImportOptionsDialog(this);
|
||||||
|
}
|
||||||
"TAB" -> {
|
"TAB" -> {
|
||||||
when(intent.getStringExtra("TAB")){
|
when(intent.getStringExtra("TAB")){
|
||||||
"Sources" -> {
|
"Sources" -> {
|
||||||
@ -730,18 +733,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||||||
if (!newPipeSubsParsed.has("subscriptions") || !newPipeSubsParsed["subscriptions"].isJsonArray)
|
if (!newPipeSubsParsed.has("subscriptions") || !newPipeSubsParsed["subscriptions"].isJsonArray)
|
||||||
return false;//throw IllegalArgumentException("Invalid NewPipe json structure found");
|
return false;//throw IllegalArgumentException("Invalid NewPipe json structure found");
|
||||||
|
|
||||||
val jsonSubs = newPipeSubsParsed["subscriptions"]
|
StateBackup.importNewPipeSubs(this, newPipeSubsParsed);
|
||||||
val jsonSubsArray = jsonSubs.asJsonArray;
|
|
||||||
val jsonSubsArrayItt = jsonSubsArray.iterator();
|
|
||||||
val subs = mutableListOf<String>()
|
|
||||||
while(jsonSubsArrayItt.hasNext()) {
|
|
||||||
val jsonSubObj = jsonSubsArrayItt.next().asJsonObject;
|
|
||||||
|
|
||||||
if(jsonSubObj.has("url"))
|
|
||||||
subs.add(jsonSubObj["url"].asString);
|
|
||||||
}
|
|
||||||
|
|
||||||
navigate(_fragImportSubscriptions, subs);
|
|
||||||
}
|
}
|
||||||
catch(ex: Exception) {
|
catch(ex: Exception) {
|
||||||
Logger.e(TAG, ex.message, ex);
|
Logger.e(TAG, ex.message, ex);
|
||||||
@ -1054,5 +1046,12 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||||||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
return sourcesIntent;
|
return sourcesIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getImportOptionsIntent(context: Context): Intent {
|
||||||
|
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||||
|
sourcesIntent.action = "IMPORT_OPTIONS";
|
||||||
|
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
return sourcesIntent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.ActivityResult
|
||||||
@ -30,6 +31,8 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||||||
|
|
||||||
private var _isFinished = false;
|
private var _isFinished = false;
|
||||||
|
|
||||||
|
lateinit var overlay: FrameLayout;
|
||||||
|
|
||||||
override fun attachBaseContext(newBase: Context?) {
|
override fun attachBaseContext(newBase: Context?) {
|
||||||
Logger.i("SettingsActivity", "SettingsActivity.attachBaseContext")
|
Logger.i("SettingsActivity", "SettingsActivity.attachBaseContext")
|
||||||
super.attachBaseContext(StateApp.instance.getLocaleContext(newBase))
|
super.attachBaseContext(StateApp.instance.getLocaleContext(newBase))
|
||||||
@ -44,6 +47,7 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||||||
_buttonDev = findViewById(R.id.button_dev);
|
_buttonDev = findViewById(R.id.button_dev);
|
||||||
_devSets = findViewById(R.id.dev_settings);
|
_devSets = findViewById(R.id.dev_settings);
|
||||||
_loaderView = findViewById(R.id.loader);
|
_loaderView = findViewById(R.id.loader);
|
||||||
|
overlay = findViewById(R.id.overlay_container);
|
||||||
|
|
||||||
_form.onChanged.subscribe { field, value ->
|
_form.onChanged.subscribe { field, value ->
|
||||||
Logger.i("SettingsActivity", "Setting [${field.field?.name}] changed, saving");
|
Logger.i("SettingsActivity", "Setting [${field.field?.name}] changed, saving");
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.futo.platformplayer.dialogs
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.Button
|
||||||
|
import com.futo.platformplayer.R
|
||||||
|
import com.futo.platformplayer.activities.MainActivity
|
||||||
|
import com.futo.platformplayer.readBytes
|
||||||
|
import com.futo.platformplayer.states.StateApp
|
||||||
|
import com.futo.platformplayer.states.StateBackup
|
||||||
|
import com.futo.platformplayer.views.buttons.BigButton
|
||||||
|
|
||||||
|
class ImportOptionsDialog: AlertDialog {
|
||||||
|
private val _context: MainActivity;
|
||||||
|
|
||||||
|
private lateinit var _button_import_zip: BigButton;
|
||||||
|
private lateinit var _button_import_ezip: BigButton;
|
||||||
|
private lateinit var _button_import_txt: BigButton;
|
||||||
|
private lateinit var _button_import_newpipe_subs: BigButton;
|
||||||
|
private lateinit var _button_close: Button;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(context: MainActivity): super(context) {
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(LayoutInflater.from(context).inflate(R.layout.dialog_import_options, null));
|
||||||
|
_button_import_zip = findViewById(R.id.button_import_zip);
|
||||||
|
_button_import_ezip = findViewById(R.id.button_import_ezip);
|
||||||
|
_button_import_txt = findViewById(R.id.button_import_txt);
|
||||||
|
_button_import_newpipe_subs = findViewById(R.id.button_import_newpipe_subs);
|
||||||
|
_button_close = findViewById(R.id.button_cancel);
|
||||||
|
|
||||||
|
_button_import_zip.onClick.subscribe {
|
||||||
|
dismiss();
|
||||||
|
StateApp.instance.requestFileReadAccess(_context, null, "application/zip") {
|
||||||
|
val zipBytes = it?.readBytes(context) ?: return@requestFileReadAccess;
|
||||||
|
StateBackup.importZipBytes(_context, StateApp.instance.scope, zipBytes);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_button_import_ezip.setOnClickListener {
|
||||||
|
|
||||||
|
}
|
||||||
|
_button_import_txt.onClick.subscribe {
|
||||||
|
dismiss();
|
||||||
|
StateApp.instance.requestFileReadAccess(_context, null, "text/plain") {
|
||||||
|
val txtBytes = it?.readBytes(context) ?: return@requestFileReadAccess;
|
||||||
|
val txt = String(txtBytes);
|
||||||
|
StateBackup.importTxt(_context, txt);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_button_import_newpipe_subs.onClick.subscribe {
|
||||||
|
dismiss();
|
||||||
|
StateApp.instance.requestFileReadAccess(_context, null, "application/json") {
|
||||||
|
val jsonBytes = it?.readBytes(context) ?: return@requestFileReadAccess;
|
||||||
|
val json = String(jsonBytes);
|
||||||
|
StateBackup.importNewPipeSubs(_context, json);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_button_close.setOnClickListener {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dismiss() {
|
||||||
|
super.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,8 +6,10 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.EditText
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.Spinner
|
import android.widget.Spinner
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.futo.platformplayer.R
|
import com.futo.platformplayer.R
|
||||||
@ -21,9 +23,13 @@ class CreatorsFragment : MainFragment() {
|
|||||||
|
|
||||||
private var _spinnerSortBy: Spinner? = null;
|
private var _spinnerSortBy: Spinner? = null;
|
||||||
private var _overlayContainer: FrameLayout? = null;
|
private var _overlayContainer: FrameLayout? = null;
|
||||||
|
private var _containerSearch: FrameLayout? = null;
|
||||||
|
private var _editSearch: EditText? = null;
|
||||||
|
|
||||||
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
val view = inflater.inflate(R.layout.fragment_creators, container, false);
|
val view = inflater.inflate(R.layout.fragment_creators, container, false);
|
||||||
|
_containerSearch = view.findViewById(R.id.container_search);
|
||||||
|
_editSearch = view.findViewById(R.id.edit_search);
|
||||||
|
|
||||||
val adapter = SubscriptionAdapter(inflater, getString(R.string.confirm_delete_subscription));
|
val adapter = SubscriptionAdapter(inflater, getString(R.string.confirm_delete_subscription));
|
||||||
adapter.onClick.subscribe { platformUser -> navigate<ChannelFragment>(platformUser) };
|
adapter.onClick.subscribe { platformUser -> navigate<ChannelFragment>(platformUser) };
|
||||||
@ -44,6 +50,10 @@ class CreatorsFragment : MainFragment() {
|
|||||||
|
|
||||||
_spinnerSortBy = spinnerSortBy;
|
_spinnerSortBy = spinnerSortBy;
|
||||||
|
|
||||||
|
_editSearch?.addTextChangedListener {
|
||||||
|
adapter.query = it.toString();
|
||||||
|
}
|
||||||
|
|
||||||
val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_subscriptions);
|
val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_subscriptions);
|
||||||
recyclerView.adapter = adapter;
|
recyclerView.adapter = adapter;
|
||||||
recyclerView.layoutManager = LinearLayoutManager(view.context);
|
recyclerView.layoutManager = LinearLayoutManager(view.context);
|
||||||
@ -54,6 +64,8 @@ class CreatorsFragment : MainFragment() {
|
|||||||
super.onDestroyMainView();
|
super.onDestroyMainView();
|
||||||
_spinnerSortBy = null;
|
_spinnerSortBy = null;
|
||||||
_overlayContainer = null;
|
_overlayContainer = null;
|
||||||
|
_editSearch = null;
|
||||||
|
_containerSearch = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -235,14 +235,33 @@ class StateApp {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestFileReadAccess(activity: IWithResultLauncher, path: Uri?, handle: (DocumentFile?)->Unit) {
|
fun requestFileReadAccess(activity: IWithResultLauncher, path: Uri?, contentType: String, handle: (DocumentFile?)->Unit) {
|
||||||
if(activity is Context) {
|
if(activity is Context) {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT);
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||||
if(path != null)
|
if(path != null)
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
|
||||||
intent.flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
intent.flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
.or(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
.or(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
intent.setType(contentType);
|
||||||
|
activity.launchForResult(intent, 98) {
|
||||||
|
if(it.resultCode == Activity.RESULT_OK) {
|
||||||
|
val uri = it.data?.data;
|
||||||
|
if(uri != null)
|
||||||
|
handle(DocumentFile.fromSingleUri(activity, uri));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UIDialogs.showDialogOk(context, R.drawable.ic_security_pred, "No access granted");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun requestFileCreateAccess(activity: IWithResultLauncher, path: Uri?, contentType: String, handle: (DocumentFile?)->Unit) {
|
||||||
|
if(activity is Context) {
|
||||||
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||||
|
if(path != null)
|
||||||
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
|
||||||
|
intent.flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
.or(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
intent.setType(contentType);
|
||||||
activity.launchForResult(intent, 98) {
|
activity.launchForResult(intent, 98) {
|
||||||
if(it.resultCode == Activity.RESULT_OK) {
|
if(it.resultCode == Activity.RESULT_OK) {
|
||||||
val uri = it.data?.data;
|
val uri = it.data?.data;
|
||||||
|
@ -8,17 +8,21 @@ import com.futo.platformplayer.R
|
|||||||
import com.futo.platformplayer.Settings
|
import com.futo.platformplayer.Settings
|
||||||
import com.futo.platformplayer.UIDialogs
|
import com.futo.platformplayer.UIDialogs
|
||||||
import com.futo.platformplayer.activities.IWithResultLauncher
|
import com.futo.platformplayer.activities.IWithResultLauncher
|
||||||
|
import com.futo.platformplayer.activities.MainActivity
|
||||||
import com.futo.platformplayer.activities.SettingsActivity
|
import com.futo.platformplayer.activities.SettingsActivity
|
||||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
||||||
import com.futo.platformplayer.copyTo
|
import com.futo.platformplayer.copyTo
|
||||||
import com.futo.platformplayer.encryption.GPasswordEncryptionProvider
|
import com.futo.platformplayer.encryption.GPasswordEncryptionProvider
|
||||||
import com.futo.platformplayer.encryption.GPasswordEncryptionProviderV0
|
import com.futo.platformplayer.encryption.GPasswordEncryptionProviderV0
|
||||||
|
import com.futo.platformplayer.fragment.mainactivity.main.ImportSubscriptionsFragment
|
||||||
import com.futo.platformplayer.getNowDiffHours
|
import com.futo.platformplayer.getNowDiffHours
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.readBytes
|
import com.futo.platformplayer.readBytes
|
||||||
import com.futo.platformplayer.stores.FragmentedStorage
|
import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||||
import com.futo.platformplayer.writeBytes
|
import com.futo.platformplayer.writeBytes
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParser
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -52,15 +56,6 @@ class StateBackup {
|
|||||||
val secondaryBackupFile = dir.findFile("GrayjayBackup.ezip.old") ?: if(create) dir.createFile("grayjay/ezip", "GrayjayBackup.ezip.old") else null;
|
val secondaryBackupFile = dir.findFile("GrayjayBackup.ezip.old") ?: if(create) dir.createFile("grayjay/ezip", "GrayjayBackup.ezip.old") else null;
|
||||||
return Pair(mainBackupFile, secondaryBackupFile);
|
return Pair(mainBackupFile, secondaryBackupFile);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
private fun getAutomaticBackupFiles(): Pair<File, File> {
|
|
||||||
val dir = StateApp.instance.getExternalRootDirectory();
|
|
||||||
if(dir == null)
|
|
||||||
throw IllegalStateException("Can't access external files");
|
|
||||||
return Pair(File(dir, "GrayjayBackup.ezip"), File(dir, "GrayjayBackup.ezip.old"))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
fun getAllMigrationStores(): List<ManagedStore<*>> = listOf(
|
fun getAllMigrationStores(): List<ManagedStore<*>> = listOf(
|
||||||
StateSubscriptions.instance.toMigrateCheck(),
|
StateSubscriptions.instance.toMigrateCheck(),
|
||||||
StatePlaylists.instance.toMigrateCheck()
|
StatePlaylists.instance.toMigrateCheck()
|
||||||
@ -192,7 +187,19 @@ class StateBackup {
|
|||||||
importZipBytes(context, scope, backupBytes);
|
importZipBytes(context, scope, backupBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startExternalBackup() {
|
fun saveExternalBackup(activity: IWithResultLauncher) {
|
||||||
|
val data = export();
|
||||||
|
if(activity is Context)
|
||||||
|
StateApp.instance.requestFileCreateAccess(activity, null, "application/zip") {
|
||||||
|
if(it == null) {
|
||||||
|
UIDialogs.toast("Cancelled");
|
||||||
|
return@requestFileCreateAccess;
|
||||||
|
}
|
||||||
|
it.writeBytes(activity, data.asZip());
|
||||||
|
UIDialogs.toast("Export saved");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
fun shareExternalBackup() {
|
||||||
val data = export();
|
val data = export();
|
||||||
val now = OffsetDateTime.now();
|
val now = OffsetDateTime.now();
|
||||||
val exportFile = File(
|
val exportFile = File(
|
||||||
@ -401,6 +408,46 @@ class StateBackup {
|
|||||||
).withCondition { doImport } else null
|
).withCondition { doImport } else null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun importTxt(context: MainActivity, text: String, allowFailure: Boolean = false): Boolean {
|
||||||
|
if(text.startsWith("@/Subscription") || text.startsWith("Subscriptions")) {
|
||||||
|
val lines = text.split("\n").map { it.trim() }.drop(1).filter { it.isNotEmpty() };
|
||||||
|
context.navigate(context.getFragment<ImportSubscriptionsFragment>(), lines);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(allowFailure) {
|
||||||
|
UIDialogs.showGeneralErrorDialog(context, "Unknown text header [${text}]");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fun importNewPipeSubs(context: MainActivity, json: String) {
|
||||||
|
val newPipeSubsParsed = JsonParser.parseString(json).asJsonObject;
|
||||||
|
if (!newPipeSubsParsed.has("subscriptions") || !newPipeSubsParsed["subscriptions"].isJsonArray)
|
||||||
|
UIDialogs.showGeneralErrorDialog(context, "Invalid json");
|
||||||
|
else {
|
||||||
|
importNewPipeSubs(context, newPipeSubsParsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun importNewPipeSubs(context: MainActivity, obj: JsonObject) {
|
||||||
|
try {
|
||||||
|
val jsonSubs = obj["subscriptions"]
|
||||||
|
val jsonSubsArray = jsonSubs.asJsonArray;
|
||||||
|
val jsonSubsArrayItt = jsonSubsArray.iterator();
|
||||||
|
val subs = mutableListOf<String>()
|
||||||
|
while(jsonSubsArrayItt.hasNext()) {
|
||||||
|
val jsonSubObj = jsonSubsArrayItt.next().asJsonObject;
|
||||||
|
|
||||||
|
if(jsonSubObj.has("url"))
|
||||||
|
subs.add(jsonSubObj["url"].asString);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.navigate(context.getFragment<ImportSubscriptionsFragment>(), subs);
|
||||||
|
}
|
||||||
|
catch(ex: Exception) {
|
||||||
|
Logger.e("StateBackup", ex.message, ex);
|
||||||
|
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_parse_newpipe_subscriptions), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExportStructure(
|
class ExportStructure(
|
||||||
|
@ -117,7 +117,8 @@ class CommentViewHolder : ViewHolder {
|
|||||||
|
|
||||||
val rating = comment.rating;
|
val rating = comment.rating;
|
||||||
if (rating is RatingLikeDislikes) {
|
if (rating is RatingLikeDislikes) {
|
||||||
_layoutComment.alpha = if (rating.dislikes > 2 && rating.dislikes.toFloat() / (rating.likes + rating.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
_layoutComment.alpha = if (Settings.instance.comments.badReputationCommentsFading &&
|
||||||
|
rating.dislikes > 2 && rating.dislikes.toFloat() / (rating.likes + rating.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
||||||
} else {
|
} else {
|
||||||
_layoutComment.alpha = 1.0f;
|
_layoutComment.alpha = 1.0f;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
|||||||
import com.futo.polycentric.core.Opinion
|
import com.futo.polycentric.core.Opinion
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import userpackage.Protocol
|
|
||||||
import java.util.IdentityHashMap
|
import java.util.IdentityHashMap
|
||||||
|
|
||||||
class CommentWithReferenceViewHolder : ViewHolder {
|
class CommentWithReferenceViewHolder : ViewHolder {
|
||||||
@ -135,7 +134,8 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||||||
|
|
||||||
val rating = comment.rating;
|
val rating = comment.rating;
|
||||||
if (rating is RatingLikeDislikes) {
|
if (rating is RatingLikeDislikes) {
|
||||||
_layoutComment.alpha = if (rating.dislikes > 2 && rating.dislikes.toFloat() / (rating.likes + rating.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
_layoutComment.alpha = if (Settings.instance.comments.badReputationCommentsFading &&
|
||||||
|
rating.dislikes > 2 && rating.dislikes.toFloat() / (rating.likes + rating.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
||||||
} else {
|
} else {
|
||||||
_layoutComment.alpha = 1.0f;
|
_layoutComment.alpha = 1.0f;
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,16 @@ class SubscriptionAdapter : RecyclerView.Adapter<SubscriptionViewHolder> {
|
|||||||
|
|
||||||
var onClick = Event1<Subscription>();
|
var onClick = Event1<Subscription>();
|
||||||
var onSettings = Event1<Subscription>();
|
var onSettings = Event1<Subscription>();
|
||||||
var sortBy: Int = 3
|
var sortBy: Int = 5
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
updateDataset()
|
updateDataset()
|
||||||
}
|
}
|
||||||
|
var query: String? = null
|
||||||
|
set(value) {
|
||||||
|
field = value;
|
||||||
|
updateDataset();
|
||||||
|
}
|
||||||
|
|
||||||
constructor(inflater: LayoutInflater, confirmationMessage: String) : super() {
|
constructor(inflater: LayoutInflater, confirmationMessage: String) : super() {
|
||||||
_inflater = inflater;
|
_inflater = inflater;
|
||||||
@ -53,6 +58,7 @@ class SubscriptionAdapter : RecyclerView.Adapter<SubscriptionViewHolder> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDataset() {
|
private fun updateDataset() {
|
||||||
|
val queryLower = query?.lowercase() ?: "";
|
||||||
_sortedDataset = when (sortBy) {
|
_sortedDataset = when (sortBy) {
|
||||||
0 -> StateSubscriptions.instance.getSubscriptions().sortedBy({ u -> u.channel.name.lowercase() })
|
0 -> StateSubscriptions.instance.getSubscriptions().sortedBy({ u -> u.channel.name.lowercase() })
|
||||||
1 -> StateSubscriptions.instance.getSubscriptions().sortedByDescending({ u -> u.channel.name.lowercase() })
|
1 -> StateSubscriptions.instance.getSubscriptions().sortedByDescending({ u -> u.channel.name.lowercase() })
|
||||||
@ -61,7 +67,9 @@ class SubscriptionAdapter : RecyclerView.Adapter<SubscriptionViewHolder> {
|
|||||||
4 -> StateSubscriptions.instance.getSubscriptions().sortedBy { it.playbackSeconds }
|
4 -> StateSubscriptions.instance.getSubscriptions().sortedBy { it.playbackSeconds }
|
||||||
5 -> StateSubscriptions.instance.getSubscriptions().sortedByDescending { it.playbackSeconds }
|
5 -> StateSubscriptions.instance.getSubscriptions().sortedByDescending { it.playbackSeconds }
|
||||||
else -> throw IllegalStateException("Invalid sorting algorithm selected.");
|
else -> throw IllegalStateException("Invalid sorting algorithm selected.");
|
||||||
}.toList();
|
}
|
||||||
|
.filter { (queryLower.isNullOrBlank() || it.channel.name.lowercase().contains(queryLower)) }
|
||||||
|
.toList();
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class SlideUpMenuItem : RelativeLayout {
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context: Context, imageRes: Int = 0, mainText: String, subText: String = "", tag: Any, call: (()->Unit)? = null, invokeParent: Boolean = true): super(context){
|
constructor(context: Context, imageRes: Int = 0, mainText: String, subText: String = "", tag: Any?, call: (()->Unit)? = null, invokeParent: Boolean = true): super(context){
|
||||||
init();
|
init();
|
||||||
_image.setImageResource(imageRes);
|
_image.setImageResource(imageRes);
|
||||||
_text.text = mainText;
|
_text.text = mainText;
|
||||||
|
@ -1,89 +1,105 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:paddingEnd="20dp"
|
|
||||||
android:background="@color/black">
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal"
|
android:orientation="vertical"
|
||||||
android:gravity="center_vertical"
|
android:paddingStart="20dp"
|
||||||
android:paddingTop="20dp"
|
android:paddingEnd="20dp"
|
||||||
android:paddingBottom="15dp">
|
android:background="@color/black">
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_back"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:paddingRight="20dp"
|
|
||||||
app:srcCompat="@drawable/ic_back_thin_white_16dp" />
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/settings"
|
|
||||||
android:textSize="24dp"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:fontFamily="@font/inter_extra_light" />
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="20dp"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
<com.futo.platformplayer.views.LoaderView
|
android:orientation="horizontal"
|
||||||
android:id="@+id/loader"
|
android:gravity="center_vertical"
|
||||||
android:layout_marginBottom="15dp"
|
android:paddingTop="20dp"
|
||||||
android:layout_marginTop="15dp"
|
android:paddingBottom="15dp">
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp" />
|
|
||||||
|
|
||||||
<com.futo.platformplayer.views.fields.FieldForm
|
<ImageButton
|
||||||
android:id="@+id/settings_form"
|
android:id="@+id/button_back"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="match_parent"
|
||||||
|
android:paddingRight="20dp"
|
||||||
|
app:srcCompat="@drawable/ic_back_thin_white_16dp" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/settings"
|
||||||
|
android:textSize="24dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:fontFamily="@font/inter_extra_light" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/dev_settings"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<TextView
|
<com.futo.platformplayer.views.LoaderView
|
||||||
|
android:id="@+id/loader"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="60dp" />
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="14dp"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:layout_margin="5dp"
|
|
||||||
android:text="@string/you_re_apparantly_a_developer" />
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/button_dev"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/developer_settings" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
<com.futo.platformplayer.views.fields.FieldForm
|
||||||
</LinearLayout>
|
android:id="@+id/settings_form"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/dev_settings"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:text="@string/you_re_apparantly_a_developer" />
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/button_dev"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/developer_settings" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/overlay_container"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="15dp">
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -4,7 +4,7 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@color/gray_1d">
|
android:background="@color/gray_1d">
|
||||||
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingTop="40dp">
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/update_spinner"
|
android:id="@+id/update_spinner"
|
||||||
android:layout_width="100dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="70dp"
|
||||||
app:srcCompat="@drawable/ic_move_up" />
|
app:srcCompat="@drawable/ic_move_up" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -46,7 +46,19 @@
|
|||||||
android:textSize="14dp"
|
android:textSize="14dp"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:fontFamily="@font/inter_regular"
|
android:fontFamily="@font/inter_regular"
|
||||||
android:layout_marginTop="30dp"
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="30dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="You can open and share files directly to Grayjay as well."
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="13dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:fontFamily="@font/inter_regular"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_marginEnd="30dp" />
|
android:layout_marginEnd="30dp" />
|
||||||
|
|
||||||
@ -55,39 +67,47 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="10dp"
|
android:paddingBottom="10dp"
|
||||||
android:layout_marginTop="28dp"
|
android:paddingTop="10dp"
|
||||||
android:layout_marginBottom="28dp">
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="10dp">
|
||||||
<com.futo.platformplayer.views.buttons.BigButton
|
<com.futo.platformplayer.views.buttons.BigButton
|
||||||
|
android:id="@+id/button_import_zip"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:scaleY="0.9"
|
||||||
|
android:scaleX="0.9"
|
||||||
app:buttonIcon="@drawable/ic_zip"
|
app:buttonIcon="@drawable/ic_zip"
|
||||||
app:buttonText="Import Grayjay export (.zip)"
|
app:buttonText="Import Grayjay export (.zip)"
|
||||||
android:layout_margin="5dp"
|
|
||||||
app:buttonBackground="@drawable/background_big_button_black"
|
app:buttonBackground="@drawable/background_big_button_black"
|
||||||
app:buttonSubText="Pick a Grayjay export zip file" />
|
app:buttonSubText="Pick a Grayjay export zip file" />
|
||||||
<com.futo.platformplayer.views.buttons.BigButton
|
<com.futo.platformplayer.views.buttons.BigButton
|
||||||
|
android:id="@+id/button_import_ezip"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:buttonIcon="@drawable/ic_encrypted"
|
app:buttonIcon="@drawable/ic_encrypted"
|
||||||
|
android:scaleY="0.9"
|
||||||
|
android:scaleX="0.9"
|
||||||
android:alpha="0.5"
|
android:alpha="0.5"
|
||||||
app:buttonBackground="@drawable/background_big_button_black"
|
app:buttonBackground="@drawable/background_big_button_black"
|
||||||
app:buttonText="Import Grayjay Auto-Backup (.ezip)"
|
app:buttonText="Import Grayjay Auto-Backup (.ezip)"
|
||||||
android:layout_margin="5dp"
|
|
||||||
app:buttonSubText="Pick a Grayjay auto-backup encrypted zip file" />
|
app:buttonSubText="Pick a Grayjay auto-backup encrypted zip file" />
|
||||||
<com.futo.platformplayer.views.buttons.BigButton
|
<com.futo.platformplayer.views.buttons.BigButton
|
||||||
|
android:id="@+id/button_import_txt"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="5dp"
|
android:scaleY="0.9"
|
||||||
|
android:scaleX="0.9"
|
||||||
app:buttonIcon="@drawable/ic_lines"
|
app:buttonIcon="@drawable/ic_lines"
|
||||||
android:alpha="0.5"
|
|
||||||
app:buttonBackground="@drawable/background_big_button_black"
|
app:buttonBackground="@drawable/background_big_button_black"
|
||||||
app:buttonText="Import Line Text file (.txt)"
|
app:buttonText="Import Line Text file (.txt)"
|
||||||
app:buttonSubText="Pick a text file with one entry per line" />
|
app:buttonSubText="Pick a text file with one entry per line" />
|
||||||
<com.futo.platformplayer.views.buttons.BigButton
|
<com.futo.platformplayer.views.buttons.BigButton
|
||||||
|
android:id="@+id/button_import_newpipe_subs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="5dp"
|
android:scaleY="0.9"
|
||||||
|
android:scaleX="0.9"
|
||||||
app:buttonIcon="@drawable/ic_play"
|
app:buttonIcon="@drawable/ic_play"
|
||||||
app:buttonBackground="@drawable/background_big_button_black"
|
app:buttonBackground="@drawable/background_big_button_black"
|
||||||
app:buttonText="Import NewPipe Subscriptions (.json)"
|
app:buttonText="Import NewPipe Subscriptions (.json)"
|
||||||
@ -98,7 +118,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/close"
|
android:text="@string/close"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="10dp"
|
||||||
android:textSize="14dp"
|
android:textSize="14dp"
|
||||||
android:fontFamily="@font/inter_regular"
|
android:fontFamily="@font/inter_regular"
|
||||||
android:textColor="@color/colorPrimary"
|
android:textColor="@color/colorPrimary"
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:textColor="#AAAAAA"
|
android:textColor="#AAAAAA"
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
android:text="source.getVideoDetails(...)"
|
android:text=""
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_marginEnd="30dp"
|
android:layout_marginEnd="30dp"
|
||||||
@ -58,6 +58,7 @@
|
|||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:background="#111111"
|
android:background="#111111"
|
||||||
android:textSize="8dp"
|
android:textSize="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
@ -16,33 +16,67 @@
|
|||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="100dp"
|
||||||
android:minHeight="0dp"
|
android:minHeight="0dp"
|
||||||
app:layout_scrollFlags="scroll"
|
app:layout_scrollFlags="scroll"
|
||||||
app:contentInsetStart="0dp"
|
app:contentInsetStart="0dp"
|
||||||
app:contentInsetEnd="0dp">
|
app:contentInsetEnd="0dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<!--Search Text-->
|
||||||
android:layout_width="wrap_content"
|
<FrameLayout
|
||||||
|
android:id="@+id/container_search"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="14dp"
|
android:visibility="visible"
|
||||||
android:textColor="@color/gray_ac"
|
android:layout_margin="10dp">
|
||||||
android:fontFamily="@font/inter_light"
|
|
||||||
android:text="@string/sort_by"
|
|
||||||
android:paddingStart="20dp" />
|
|
||||||
|
|
||||||
<Spinner
|
<EditText
|
||||||
android:id="@+id/spinner_sortby"
|
android:id="@+id/edit_search"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:hint="Search"
|
||||||
|
android:paddingEnd="46dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_clear_search"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingEnd="18dp"
|
||||||
|
android:layout_gravity="right|center_vertical"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:src="@drawable/ic_clear_16dp" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="20dp"
|
android:gravity="center_vertical">
|
||||||
android:paddingEnd="20dp" />
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="14dp"
|
||||||
|
android:textColor="@color/gray_ac"
|
||||||
|
android:fontFamily="@font/inter_light"
|
||||||
|
android:text="@string/sort_by"
|
||||||
|
android:paddingStart="20dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner_sortby"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
@ -370,6 +370,8 @@
|
|||||||
<string name="preferred_preview_quality_description">Default quality while previewing a video in a feed</string>
|
<string name="preferred_preview_quality_description">Default quality while previewing a video in a feed</string>
|
||||||
<string name="primary_language">Primary Language</string>
|
<string name="primary_language">Primary Language</string>
|
||||||
<string name="default_comment_section">Default Comment Section</string>
|
<string name="default_comment_section">Default Comment Section</string>
|
||||||
|
<string name="bad_reputation_comments_fading">Bad Reputation Comment Fading</string>
|
||||||
|
<string name="bad_reputation_comments_fading_description">If comments with a very bad reputation should be faded. Disabling may worsen experience.</string>
|
||||||
<string name="reinstall_embedded_plugins">Reinstall Embedded Plugins</string>
|
<string name="reinstall_embedded_plugins">Reinstall Embedded Plugins</string>
|
||||||
<string name="remove_cached_version">Remove Cached Version</string>
|
<string name="remove_cached_version">Remove Cached Version</string>
|
||||||
<string name="remove_the_last_downloaded_version">Remove the last downloaded version</string>
|
<string name="remove_the_last_downloaded_version">Remove the last downloaded version</string>
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 8f10daba1ef9cbcd99f3c640d86808f8c94aa84a
|
Subproject commit 07aa5a9aab441657f89ae14ff3cfd9d9ca977fe6
|
@ -1 +1 @@
|
|||||||
Subproject commit 8f10daba1ef9cbcd99f3c640d86808f8c94aa84a
|
Subproject commit 07aa5a9aab441657f89ae14ff3cfd9d9ca977fe6
|
Loading…
x
Reference in New Issue
Block a user