mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-19 19:14:51 +00:00
Finished moving strings to strings.xml for activities and fragments.
This commit is contained in:
parent
35f9173980
commit
206c3884e9
33 changed files with 393 additions and 213 deletions
|
@ -96,8 +96,8 @@ class AddSourceActivity : AppCompatActivity() {
|
|||
var url = intent?.dataString;
|
||||
|
||||
if(url == null)
|
||||
UIDialogs.showDialog(this, R.drawable.ic_error, "No valid URL provided..", null, null,
|
||||
0, UIDialogs.Action("Ok", { finish() }, UIDialogs.ActionStyle.PRIMARY));
|
||||
UIDialogs.showDialog(this, R.drawable.ic_error, getString(R.string.no_valid_url_provided), null, null,
|
||||
0, UIDialogs.Action(getString(R.string.ok), { finish() }, UIDialogs.ActionStyle.PRIMARY));
|
||||
else {
|
||||
if(url.startsWith("vfuto://"))
|
||||
url = "https://" + url.substring("vfuto://".length);
|
||||
|
@ -129,14 +129,14 @@ class AddSourceActivity : AppCompatActivity() {
|
|||
Logger.e(TAG, "Failed decode config", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showDialog(this@AddSourceActivity, R.drawable.ic_error,
|
||||
"Invalid Config Format", null, null,
|
||||
getString(R.string.invalid_config_format), null, null,
|
||||
0, UIDialogs.Action("Ok", { finish() }, UIDialogs.ActionStyle.PRIMARY));
|
||||
};
|
||||
return@launch;
|
||||
} catch(ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch config", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, "Failed to fetch configuration", ex);
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, getString(R.string.failed_to_fetch_configuration), ex);
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class AddSourceActivity : AppCompatActivity() {
|
|||
} catch (ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch script", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, "Failed to fetch script", ex);
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, getString(R.string.failed_to_fetch_script), ex);
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
@ -175,8 +175,8 @@ class AddSourceActivity : AppCompatActivity() {
|
|||
_sourcePermissions.addView(
|
||||
SourceInfoView(this,
|
||||
R.drawable.ic_language,
|
||||
"URL Access",
|
||||
"The plugin will have access to the following domains",
|
||||
getString(R.string.url_access),
|
||||
getString(R.string.the_plugin_will_have_access_to_the_following_domains),
|
||||
config.allowUrls, true)
|
||||
)
|
||||
|
||||
|
@ -184,8 +184,8 @@ class AddSourceActivity : AppCompatActivity() {
|
|||
_sourcePermissions.addView(
|
||||
SourceInfoView(this,
|
||||
R.drawable.ic_code,
|
||||
"Eval Access",
|
||||
"The plugin will have access to eval capability (remote injection)",
|
||||
getString(R.string.eval_access),
|
||||
getString(R.string.the_plugin_will_have_access_to_eval_capability_remote_injection),
|
||||
config.allowUrls, true)
|
||||
)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class AddSourceOptionsActivity : AppCompatActivity() {
|
|||
scanResult?.let {
|
||||
val content = it.contents
|
||||
if (content == null) {
|
||||
UIDialogs.toast(this, "Failed to scan QR code")
|
||||
UIDialogs.toast(this, getString(R.string.failed_to_scan_qr_code))
|
||||
return@let
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class AddSourceOptionsActivity : AppCompatActivity() {
|
|||
} else if (content.startsWith("grayjay://plugin/")) {
|
||||
content.substring("grayjay://plugin/".length)
|
||||
} else {
|
||||
UIDialogs.toast(this, "Not a plugin URL")
|
||||
UIDialogs.toast(this, getString(R.string.not_a_plugin_url))
|
||||
return@let;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class AddSourceOptionsActivity : AppCompatActivity() {
|
|||
_buttonQR.onClick.subscribe {
|
||||
val integrator = IntentIntegrator(this);
|
||||
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
|
||||
integrator.setPrompt("Scan a QR Code")
|
||||
integrator.setPrompt(getString(R.string.scan_a_qr_code))
|
||||
integrator.setOrientationLocked(true);
|
||||
integrator.setCameraId(0)
|
||||
integrator.setBeepEnabled(false)
|
||||
|
@ -69,7 +69,7 @@ class AddSourceOptionsActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
_buttonURL.onClick.subscribe {
|
||||
UIDialogs.toast(this, "Not implemented yet..");
|
||||
UIDialogs.toast(this, getString(R.string.not_implemented_yet));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ class ExceptionActivity : AppCompatActivity() {
|
|||
_buttonRestart = findViewById(R.id.button_restart);
|
||||
_buttonClose = findViewById(R.id.button_close);
|
||||
|
||||
val context = intent.getStringExtra(EXTRA_CONTEXT) ?: "Unknown Context";
|
||||
val stack = intent.getStringExtra(EXTRA_STACK) ?: "Something went wrong... missing stack trace?";
|
||||
val context = intent.getStringExtra(EXTRA_CONTEXT) ?: getString(R.string.unknown_context);
|
||||
val stack = intent.getStringExtra(EXTRA_STACK) ?: getString(R.string.something_went_wrong_missing_stack_trace);
|
||||
|
||||
val exceptionString = "Version information (version_name = ${BuildConfig.VERSION_NAME}, version_code = ${BuildConfig.VERSION_CODE}, flavor = ${BuildConfig.FLAVOR}, build_type = ${BuildConfig.BUILD_TYPE})\n" +
|
||||
"Device information (brand= ${Build.BRAND}, manufacturer = ${Build.MANUFACTURER}, device = ${Build.DEVICE}, version-sdk = ${Build.VERSION.SDK_INT}, version-os = ${Build.VERSION.BASE_OS})\n\n" +
|
||||
|
@ -79,13 +79,13 @@ class ExceptionActivity : AppCompatActivity() {
|
|||
|
||||
private fun submitFile() {
|
||||
if (_submitted) {
|
||||
Toast.makeText(this, "Logs already submitted.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, getString(R.string.logs_already_submitted), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
val file = _file;
|
||||
if (file == null) {
|
||||
Toast.makeText(this, "No logs found.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, getString(R.string.no_logs_found), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,14 +101,14 @@ class ExceptionActivity : AppCompatActivity() {
|
|||
withContext(Dispatchers.Main) {
|
||||
if (id == null) {
|
||||
try {
|
||||
Toast.makeText(this@ExceptionActivity, "Failed automated share, share manually?", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this@ExceptionActivity, getString(R.string.failed_automated_share_share_manually), Toast.LENGTH_LONG).show();
|
||||
} catch (e: Throwable) {
|
||||
//Ignored
|
||||
}
|
||||
} else {
|
||||
_submitted = true;
|
||||
file.delete();
|
||||
Toast.makeText(this@ExceptionActivity, "Shared $id", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this@ExceptionActivity, getString(R.string.shared_id).replace("{id}", id), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,10 +119,10 @@ class ExceptionActivity : AppCompatActivity() {
|
|||
val i = Intent(Intent.ACTION_SEND);
|
||||
i.type = "text/plain";
|
||||
i.putExtra(Intent.EXTRA_EMAIL, arrayOf("grayjay@futo.org"));
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, "Unhandled exception in VS");
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.unhandled_exception_in_vs));
|
||||
i.putExtra(Intent.EXTRA_TEXT, exceptionString);
|
||||
|
||||
startActivity(Intent.createChooser(i, "Send exception to developers..."));
|
||||
startActivity(Intent.createChooser(i, getString(R.string.send_exception_to_developers)));
|
||||
} catch (e: Throwable) {
|
||||
//Ignored
|
||||
|
||||
|
|
|
@ -478,13 +478,13 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
if(targetData.startsWith("grayjay://license/")) {
|
||||
if(StatePayment.instance.setPaymentLicenseUrl(targetData))
|
||||
{
|
||||
UIDialogs.showDialogOk(this, R.drawable.ic_check, "Your license key has been set!\nAn 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)
|
||||
closeSegment(fragCurrent);
|
||||
}
|
||||
else
|
||||
UIDialogs.toast("Invalid license format");
|
||||
UIDialogs.toast(getString(R.string.invalid_license_format));
|
||||
|
||||
}
|
||||
else if(targetData.startsWith("grayjay://plugin/")) {
|
||||
|
@ -499,7 +499,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
UIDialogs.showSingleButtonDialog(
|
||||
this,
|
||||
R.drawable.ic_play,
|
||||
"Unknown content format [${targetData}]",
|
||||
getString(R.string.unknown_content_format) + " [${targetData}]",
|
||||
"Ok",
|
||||
{ });
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
UIDialogs.showSingleButtonDialog(
|
||||
this,
|
||||
R.drawable.ic_play,
|
||||
"Unknown file format [${targetData}]",
|
||||
getString(R.string.unknown_file_format) + " [${targetData}]",
|
||||
"Ok",
|
||||
{ });
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
UIDialogs.showSingleButtonDialog(
|
||||
this,
|
||||
R.drawable.ic_play,
|
||||
"Unknown Polycentric format [${targetData}]",
|
||||
getString(R.string.unknown_polycentric_format) + " [${targetData}]",
|
||||
"Ok",
|
||||
{ });
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
UIDialogs.showSingleButtonDialog(
|
||||
this,
|
||||
R.drawable.ic_play,
|
||||
"Unknown url format [${targetData}]",
|
||||
getString(R.string.unknown_url_format) + " [${targetData}]",
|
||||
"Ok",
|
||||
{ });
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
}
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
UIDialogs.showGeneralErrorDialog(this, "Failed to handle file", ex);
|
||||
UIDialogs.showGeneralErrorDialog(this, getString(R.string.failed_to_handle_file), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,7 +603,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
val store: ManagedStore<*> = when(type) {
|
||||
"Playlist" -> StatePlaylists.instance.playlistStore
|
||||
else -> {
|
||||
UIDialogs.toast("Unknown reconstruction type ${type}", false);
|
||||
UIDialogs.toast(getString(R.string.unknown_reconstruction_type) + " ${type}", false);
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
@ -646,7 +646,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
}
|
||||
catch(ex: Exception) {
|
||||
Logger.e(TAG, ex.message, ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to parse NewPipe Subscriptions", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, getString(R.string.failed_to_parse_newpipe_subscriptions), ex);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -53,7 +53,7 @@ class PolycentricBackupActivity : AppCompatActivity() {
|
|||
val qrCodeBitmap = generateQRCode(_exportBundle, dimension, dimension);
|
||||
_imageQR.setImageBitmap(qrCodeBitmap);
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to generate QR code", e);
|
||||
Logger.e(TAG, getString(R.string.failed_to_generate_qr_code), e);
|
||||
_imageQR.visibility = View.INVISIBLE;
|
||||
_textQR.visibility = View.INVISIBLE;
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ class PolycentricBackupActivity : AppCompatActivity() {
|
|||
type = "text/plain";
|
||||
putExtra(Intent.EXTRA_TEXT, _exportBundle);
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, "Share Text"));
|
||||
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_text)));
|
||||
};
|
||||
|
||||
_buttonCopy.onClick.subscribe {
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager;
|
||||
val clip = ClipData.newPlainText("Copied Text", _exportBundle);
|
||||
val clip = ClipData.newPlainText(getString(R.string.copied_text), _exportBundle);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
try {
|
||||
val username = _profileName.text.toString();
|
||||
if (username.length < 3) {
|
||||
UIDialogs.toast(this@PolycentricCreateProfileActivity, "Must be at least 3 characters long.");
|
||||
UIDialogs.toast(this@PolycentricCreateProfileActivity, getString(R.string.must_be_at_least_3_characters_long));
|
||||
return@setOnClickListener;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
processHandle.setUsername(username);
|
||||
StatePolycentric.instance.setProcessHandle(processHandle);
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to create profile .", e);
|
||||
Logger.e(TAG, getString(R.string.failed_to_create_profile), e);
|
||||
return@launch;
|
||||
} finally {
|
||||
_creating = false;
|
||||
|
@ -77,7 +77,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
try {
|
||||
processHandle.fullyBackfillServers();
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to fully backfill servers.");
|
||||
Logger.e(TAG, getString(R.string.failed_to_fully_backfill_servers));
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
@ -47,7 +47,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
|
|||
this.setMargins(0, 0, 0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, resources.displayMetrics).toInt());
|
||||
};
|
||||
profileButton.withPrimaryText(systemState.username);
|
||||
profileButton.withSecondaryText("Sign in to this identity");
|
||||
profileButton.withSecondaryText(getString(R.string.sign_in_to_this_identity));
|
||||
profileButton.onClick.subscribe {
|
||||
StatePolycentric.instance.setProcessHandle(processHandle);
|
||||
startActivity(Intent(this@PolycentricHomeActivity, PolycentricProfileActivity::class.java));
|
||||
|
|
|
@ -59,7 +59,7 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
|||
_buttonScanProfile.setOnClickListener {
|
||||
val integrator = IntentIntegrator(this)
|
||||
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
|
||||
integrator.setPrompt("Scan a QR code")
|
||||
integrator.setPrompt(getString(R.string.scan_a_qr_code))
|
||||
integrator.setOrientationLocked(true);
|
||||
integrator.setCameraId(0)
|
||||
integrator.setBeepEnabled(false)
|
||||
|
@ -70,7 +70,7 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
|||
|
||||
_buttonImportProfile.setOnClickListener {
|
||||
if (_editProfile.text.isEmpty()) {
|
||||
UIDialogs.toast(this, "Text field does not contain any data");
|
||||
UIDialogs.toast(this, getString(R.string.text_field_does_not_contain_any_data));
|
||||
return@setOnClickListener;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
|||
|
||||
private fun import(url: String) {
|
||||
if (!url.startsWith("polycentric://")) {
|
||||
UIDialogs.toast(this, "Not a valid URL");
|
||||
UIDialogs.toast(this, getString(R.string.not_a_valid_url));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
|||
|
||||
val existingProcessSecret = Store.instance.getProcessSecret(keyPair.publicKey);
|
||||
if (existingProcessSecret != null) {
|
||||
UIDialogs.toast(this, "This profile is already imported");
|
||||
UIDialogs.toast(this, getString(R.string.this_profile_is_already_imported));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
|||
finish();
|
||||
} catch (e: Throwable) {
|
||||
Logger.w(TAG, "Failed to import profile", e);
|
||||
UIDialogs.toast(this, "Failed to import profile: '${e.message}'");
|
||||
UIDialogs.toast(this, getString(R.string.failed_to_import_profile) + " '${e.message}'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
}
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Failed to backfill client");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.failed_to_backfill_client));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,10 +101,10 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
_buttonDelete.onClick.subscribe {
|
||||
UIDialogs.showConfirmationDialog(this, "Are you sure you want to remove this profile?", {
|
||||
UIDialogs.showConfirmationDialog(this, getString(R.string.are_you_sure_you_want_to_remove_this_profile), {
|
||||
val processHandle = StatePolycentric.instance.processHandle;
|
||||
if (processHandle == null) {
|
||||
UIDialogs.toast(this, "No process handle set");
|
||||
UIDialogs.toast(this, getString(R.string.no_process_handle_set));
|
||||
return@showConfirmationDialog;
|
||||
}
|
||||
|
||||
|
@ -122,13 +122,13 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
var hasChanges = false;
|
||||
val username = _editName.text.toString();
|
||||
if (username.length < 3) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Name must be at least 3 characters long");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.name_must_be_at_least_3_characters_long));
|
||||
return@launch;
|
||||
}
|
||||
|
||||
val processHandle = StatePolycentric.instance.processHandle;
|
||||
if (processHandle == null) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Process handle unset");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.process_handle_unset));
|
||||
return@launch;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
val bytes = readBytesFromUri(applicationContext.contentResolver, avatarUri);
|
||||
if (bytes == null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Failed to read image");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.failed_to_read_image));
|
||||
}
|
||||
|
||||
return@launch;
|
||||
|
@ -188,12 +188,12 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
try {
|
||||
processHandle.fullyBackfillServers();
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Changes have been saved");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.changes_have_been_saved));
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Logger.w(TAG, "Failed to synchronize changes", e);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, "Failed to synchronize changes");
|
||||
UIDialogs.toast(this@PolycentricProfileActivity, getString(R.string.failed_to_synchronize_changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
UIDialogs.toast(this, ImagePicker.getError(data));
|
||||
} else {
|
||||
UIDialogs.toast(this, "Image picker cancelled");
|
||||
UIDialogs.toast(this, getString(R.string.image_picker_cancelled));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||
SettingsDev.instance.developerMode = true;
|
||||
SettingsDev.instance.save();
|
||||
updateDevMode();
|
||||
UIDialogs.toast(this, "You are now in developer mode");
|
||||
UIDialogs.toast(this, getString(R.string.you_are_now_in_developer_mode));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -77,7 +77,7 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
|
|||
};
|
||||
_textName?.text = channel.name;
|
||||
|
||||
val metadata = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} subscribers" else "";
|
||||
val metadata = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} " + getString(R.string.subscribers).lowercase() else "";
|
||||
_textMetadata?.text = metadata;
|
||||
_lastChannel = channel;
|
||||
setLinks(channel.links, channel.name);
|
||||
|
@ -91,7 +91,7 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
|
|||
l.removeAllViews();
|
||||
|
||||
if (links.isNotEmpty()) {
|
||||
_textFindOn?.text = "Find $name on";
|
||||
_textFindOn?.text = getString(R.string.find_name_on).replace("{name}", name);
|
||||
_textFindOn?.visibility = View.VISIBLE;
|
||||
|
||||
for (pair in links) {
|
||||
|
|
|
@ -56,7 +56,7 @@ class ChannelListFragment : Fragment, IChannelTabFragment {
|
|||
}.exception<ScriptCaptchaRequiredException> { }
|
||||
.exceptionWithParameter<Throwable> { ex, para ->
|
||||
Logger.w(ChannelFragment.TAG, "Failed to load results.", ex);
|
||||
UIDialogs.toast(requireContext(), "Failed to fetch\n${para}", false)
|
||||
UIDialogs.toast(requireContext(), getString(R.string.failed_to_fetch) + "\n " + para, false)
|
||||
loadNext();
|
||||
};
|
||||
|
||||
|
|
|
@ -60,12 +60,12 @@ class BuyFragment : MainFragment() {
|
|||
|
||||
_paymentManager = PaymentManager(StatePayment.instance, fragment, _overlayPaying) { success, purchaseId, exception ->
|
||||
if(success) {
|
||||
UIDialogs.showDialog(context, R.drawable.ic_check, "Payment succeeded", "Thanks for your purchase, a key will be sent to your email after your payment has been received!", null, 0,
|
||||
UIDialogs.showDialog(context, R.drawable.ic_check, context.getString(R.string.payment_succeeded), context.getString(R.string.thanks_for_your_purchase_a_key_will_be_sent_to_your_email_after_your_payment_has_been_received), null, 0,
|
||||
UIDialogs.Action("Ok", {}, UIDialogs.ActionStyle.PRIMARY));
|
||||
_fragment.close(true);
|
||||
}
|
||||
else {
|
||||
UIDialogs.showGeneralErrorDialog(context, "Payment failed", exception);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.payment_failed), exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,12 +107,12 @@ class BuyFragment : MainFragment() {
|
|||
}
|
||||
|
||||
private fun paid() {
|
||||
val licenseInput = SlideUpMenuTextInput(context, "License");
|
||||
val productLicenseDialog = SlideUpMenuOverlay(context, findViewById<FrameLayout>(R.id.overlay_paid), "Enter license key", "Ok", true, licenseInput);
|
||||
val licenseInput = SlideUpMenuTextInput(context, context.getString(R.string.license));
|
||||
val productLicenseDialog = SlideUpMenuOverlay(context, findViewById<FrameLayout>(R.id.overlay_paid), context.getString(R.string.enter_license_key), context.getString(R.string.ok), true, licenseInput);
|
||||
productLicenseDialog.onOK.subscribe {
|
||||
val licenseText = licenseInput.text;
|
||||
if (licenseText.isNullOrEmpty()) {
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_error_pred, "Invalid license key");
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_error_pred, context.getString(R.string.invalid_license_key));
|
||||
return@subscribe;
|
||||
}
|
||||
|
||||
|
@ -127,19 +127,19 @@ class BuyFragment : MainFragment() {
|
|||
licenseInput.clear();
|
||||
productLicenseDialog.hide(true);
|
||||
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_check, "Your license key has been set!\nAn app restart might be required.");
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_check, context.getString(R.string.your_license_key_has_been_set_an_app_restart_might_be_required));
|
||||
_fragment.close(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_error_pred, "Invalid license key");
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_error_pred, context.getString(R.string.invalid_license_key));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e("BuyFragment", "Failed to activate key", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to activate key", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_activate_key), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ class ChannelFragment : MainFragment() {
|
|||
|
||||
UIDialogs.showDialog(context,
|
||||
R.drawable.ic_sources,
|
||||
"No source enabled to support this channel\n(${_url})", null, null,
|
||||
context.getString(R.string.no_source_enabled_to_support_this_channel) + "\n(${_url})", null, null,
|
||||
0,
|
||||
UIDialogs.Action("Back", {
|
||||
fragment.close(true);
|
||||
|
@ -344,19 +344,19 @@ class ChannelFragment : MainFragment() {
|
|||
_fragment.topBar?.onShown(channel);
|
||||
|
||||
val buttons = arrayListOf(Pair(R.drawable.ic_playlist_add) {
|
||||
UIDialogs.showConfirmationDialog(context, "Do you want to convert channel ${channel.name} to a playlist?", {
|
||||
UIDialogs.showConfirmationDialog(context, context.getString(R.string.do_you_want_to_convert_channel_channelname_to_a_playlist).replace("{channelName}", channel.name), {
|
||||
UIDialogs.showDialogProgress(context) {
|
||||
_fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
StatePlaylists.instance.createPlaylistFromChannel(channel) { page ->
|
||||
_fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||
it.setText("${channel.name}\nPage ${page}");
|
||||
it.setText("${channel.name}\n" + context.getString(R.string.page) + " $page");
|
||||
}
|
||||
};
|
||||
}
|
||||
catch(ex: Exception) {
|
||||
Logger.e(TAG, "Error", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to convert channel", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_convert_channel), ex);
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
@ -377,7 +377,7 @@ class ChannelFragment : MainFragment() {
|
|||
_fragment.topBar?.assume<NavigationTopBarFragment>()?.setMenuItems(buttons);
|
||||
|
||||
_buttonSubscribe.setSubscribeChannel(channel);
|
||||
_textChannelSub.text = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} subscribers" else "";
|
||||
_textChannelSub.text = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} " + context.getString(R.string.subscribers).lowercase() else "";
|
||||
|
||||
//TODO: Find a better way to access the adapter fragments..
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
|||
//TODO: Reconstruct search video from detail if search is null
|
||||
_overlayContainer.let {
|
||||
if(content is IPlatformVideo)
|
||||
UISlideOverlays.showVideoOptionsOverlay(content, it, SlideUpMenuItem(context, R.drawable.ic_visibility_off, "Hide", "Hide from Home", "hide",
|
||||
UISlideOverlays.showVideoOptionsOverlay(content, it, SlideUpMenuItem(context, R.drawable.ic_visibility_off, context.getString(R.string.hide), context.getString(R.string.hide_from_home), "hide",
|
||||
{ StateMeta.instance.addHiddenVideo(content.url);
|
||||
if (fragment is HomeFragment) {
|
||||
val removeIndex = recyclerData.results.indexOf(content);
|
||||
|
@ -82,7 +82,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
|||
}
|
||||
}
|
||||
}),
|
||||
SlideUpMenuItem(context, R.drawable.ic_playlist, "Play Feed as Queue", "Play entire feed", "playFeed",
|
||||
SlideUpMenuItem(context, R.drawable.ic_playlist, context.getString(R.string.play_feed_as_queue), context.getString(R.string.play_entire_feed), "playFeed",
|
||||
{
|
||||
val newQueue = listOf(content) + recyclerData.results
|
||||
.filterIsInstance<IPlatformVideo>()
|
||||
|
@ -96,7 +96,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
|||
if(it is IPlatformVideo) {
|
||||
StatePlayer.instance.addToQueue(it);
|
||||
val name = if (it.name.length > 20) (it.name.subSequence(0, 20).toString() + "...") else it.name;
|
||||
UIDialogs.toast(context, "Queued [$name]", false);
|
||||
UIDialogs.toast(context, context.getString(R.string.queued) + " [$name]", false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class ContentSearchResultsFragment : MainFragment() {
|
|||
})
|
||||
.success { loadedResult(it); }.exception<ScriptCaptchaRequiredException> { }
|
||||
.exception<Throwable> {
|
||||
Logger.w(ChannelFragment.TAG, "Failed to load results.", it);
|
||||
Logger.w(TAG, "Failed to load results.", it);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, it.message ?: "", it, { loadResults() });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,8 +136,8 @@ class DownloadsFragment : MainFragment() {
|
|||
|
||||
fun reloadUI() {
|
||||
val usage = StateDownloads.instance.getTotalUsage(true);
|
||||
_usageUsed.text = "${usage.usage.toHumanBytesSize()} Used";
|
||||
_usageAvailable.text = "${usage.available.toHumanBytesSize()} Available";
|
||||
_usageUsed.text = "${usage.usage.toHumanBytesSize()} " + context.getString(R.string.used);
|
||||
_usageAvailable.text = "${usage.available.toHumanBytesSize()} " + context.getString(R.string.available);
|
||||
_usageProgress.progress = usage.percentage.toFloat();
|
||||
|
||||
|
||||
|
@ -161,7 +161,7 @@ class DownloadsFragment : MainFragment() {
|
|||
_listPlaylistsContainer.visibility = GONE;
|
||||
else {
|
||||
_listPlaylistsContainer.visibility = VISIBLE;
|
||||
_listPlaylistsMeta.text = "(${playlists.size} playlists, ${playlists.sumOf { it.playlist.videos.size }} videos)";
|
||||
_listPlaylistsMeta.text = "(${playlists.size} ${context.getString(R.string.playlists).lowercase()}, ${playlists.sumOf { it.playlist.videos.size }} ${context.getString(R.string.videos).lowercase()})";
|
||||
|
||||
_listPlaylists.removeAllViews();
|
||||
for(view in playlists.map { PlaylistDownloadItem(context, it) }) {
|
||||
|
@ -176,7 +176,7 @@ class DownloadsFragment : MainFragment() {
|
|||
_listDownloadedHeader.visibility = GONE;
|
||||
} else {
|
||||
_listDownloadedHeader.visibility = VISIBLE;
|
||||
_listDownloadedMeta.text = "(${downloaded.size} videos)";
|
||||
_listDownloadedMeta.text = "(${downloaded.size} ${context.getString(R.string.videos).lowercase()})";
|
||||
}
|
||||
|
||||
_listDownloaded.setData(downloaded);
|
||||
|
|
|
@ -144,7 +144,7 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
|
|||
recyclerData.adapter.notifyItemRangeInserted(recyclerData.adapter.childToParentPosition(posBefore), filteredResults.size);
|
||||
}.exception<Throwable> {
|
||||
Logger.w(TAG, "Failed to load next page.", it);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to load next page", it, {
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_next_page), it, {
|
||||
loadNextPage();
|
||||
});
|
||||
//UIDialogs.showDataRetryDialog(layoutInflater, it.message, { loadNextPage() });
|
||||
|
@ -256,7 +256,7 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
|
|||
fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||
try {
|
||||
if(jsVideoPager != null)
|
||||
UIDialogs.toast(it, "Plugin ${jsVideoPager.getPluginConfig().name} failed:\n${kv.value.message}", false);
|
||||
UIDialogs.toast(it, context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", jsVideoPager.getPluginConfig().name).replace("{message}", kv.value.message ?: ""), false);
|
||||
else
|
||||
UIDialogs.toast(it, kv.value.message ?: "", false);
|
||||
} catch (e: Throwable) {
|
||||
|
@ -333,11 +333,11 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
|
|||
parentPager.onPagerError.subscribe(this) {
|
||||
Logger.e(TAG, "Search pager failed: ${it.message}", it);
|
||||
when (it) {
|
||||
is PluginException -> UIDialogs.toast("Plugin [${it.config.name}] failed due to:\n${it.message}")
|
||||
is PluginException -> UIDialogs.toast("Plugin [{pluginName}] failed due to:\n{exceptionMessage}".replace("{pluginName}", it.config.name).replace("{exceptionMessage}", it.message ?: ""))
|
||||
is CancellationException -> {
|
||||
//Hide cancelled toast
|
||||
}
|
||||
else -> UIDialogs.toast("Plugin failed due to:\n${it.message}")
|
||||
else -> UIDialogs.toast(context.getString(R.string.plugin_failed_due_to) + "\n${it.message}")
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -101,21 +101,21 @@ class HomeFragment : MainFragment() {
|
|||
.exception<ScriptCaptchaRequiredException> { }
|
||||
.exception<ScriptExecutionException> {
|
||||
Logger.w(ChannelFragment.TAG, "Plugin failure.", it);
|
||||
UIDialogs.showDialog(context, R.drawable.ic_error_pred, "Failed to get Home\nPlugin [${it.config.name}]", it.message, null, 0,
|
||||
UIDialogs.Action("Ignore", {}),
|
||||
UIDialogs.Action("Sources", { fragment.navigate<SourcesFragment>() }, UIDialogs.ActionStyle.PRIMARY)
|
||||
UIDialogs.showDialog(context, R.drawable.ic_error_pred, context.getString(R.string.failed_to_get_home_plugin) + " [${it.config.name}]", it.message, null, 0,
|
||||
UIDialogs.Action(context.getString(R.string.ignore), {}),
|
||||
UIDialogs.Action(context.getString(R.string.sources), { fragment.navigate<SourcesFragment>() }, UIDialogs.ActionStyle.PRIMARY)
|
||||
);
|
||||
}
|
||||
.exception<ScriptImplementationException> {
|
||||
Logger.w(TAG, "Plugin failure.", it);
|
||||
UIDialogs.showDialog(context, R.drawable.ic_error_pred, "Failed to get Home\nPlugin [${it.config.name}]", it.message, null, 0,
|
||||
UIDialogs.Action("Ignore", {}),
|
||||
UIDialogs.Action("Sources", { fragment.navigate<SourcesFragment>() }, UIDialogs.ActionStyle.PRIMARY)
|
||||
UIDialogs.showDialog(context, R.drawable.ic_error_pred, context.getString(R.string.failed_to_get_home_plugin) + " [${it.config.name}]", it.message, null, 0,
|
||||
UIDialogs.Action(context.getString(R.string.ignore), {}),
|
||||
UIDialogs.Action(context.getString(R.string.sources), { fragment.navigate<SourcesFragment>() }, UIDialogs.ActionStyle.PRIMARY)
|
||||
);
|
||||
}
|
||||
.exception<Throwable> {
|
||||
Logger.w(TAG, "Failed to load channel.", it);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to get Home", it, {
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_get_home), it, {
|
||||
loadResults()
|
||||
}) {
|
||||
finishRefreshLayoutLoader();
|
||||
|
@ -159,7 +159,7 @@ class HomeFragment : MainFragment() {
|
|||
}
|
||||
private fun loadedResult(pager : IPager<IPlatformContent>) {
|
||||
if (pager is EmptyPager<IPlatformContent>) {
|
||||
StateAnnouncement.instance.registerAnnouncement(UUID.randomUUID().toString(), "No home available", "No home page is available, please check if you are connected to the internet and refresh.", AnnouncementType.SESSION);
|
||||
StateAnnouncement.instance.registerAnnouncement(UUID.randomUUID().toString(), context.getString(R.string.no_home_available), context.getString(R.string.no_home_page_is_available_please_check_if_you_are_connected_to_the_internet_and_refresh), AnnouncementType.SESSION);
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Got new home pager ${pager}");
|
||||
|
|
|
@ -113,7 +113,7 @@ class ImportPlaylistsFragment : MainFragment() {
|
|||
}.exceptionWithParameter<Throwable> { ex, para ->
|
||||
//setLoading(false);
|
||||
Logger.w(ChannelFragment.TAG, "Failed to load results.", ex);
|
||||
UIDialogs.toast(context, "Failed to fetch\n${para}", false)
|
||||
UIDialogs.toast(context, context.getString(R.string.failed_to_fetch) + "\n${para}", false)
|
||||
//UIDialogs.showDataRetryDialog(layoutInflater, { load(); });
|
||||
loadNext();
|
||||
};
|
||||
|
@ -144,14 +144,14 @@ class ImportPlaylistsFragment : MainFragment() {
|
|||
|
||||
val tb = _fragment.topBar as ImportTopBarFragment?;
|
||||
tb?.let {
|
||||
it.title = "Import Playlists";
|
||||
it.title = context.getString(R.string.import_playlists);
|
||||
it.onImport.subscribe(this) {
|
||||
val playlistsToImport = _items.filter { i -> i.selected }.toList();
|
||||
for (playlistToImport in playlistsToImport) {
|
||||
StatePlaylists.instance.createOrUpdatePlaylist(playlistToImport.playlist);
|
||||
}
|
||||
|
||||
UIDialogs.toast("${playlistsToImport.size} playlists imported.");
|
||||
UIDialogs.toast("${playlistsToImport.size} " + context.getString(R.string.playlists_imported));
|
||||
_fragment.closeSegment();
|
||||
};
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ class ImportPlaylistsFragment : MainFragment() {
|
|||
val itemsSelected = _items.count { i -> i.selected };
|
||||
if (itemsSelected > 0) {
|
||||
_textSelectDeselectAll.text = context.getString(R.string.deselect_all);
|
||||
_textCounter.text = "$itemsSelected out of ${_items.size} selected";
|
||||
_textCounter.text = context.getString(R.string.index_out_of_size_selected).replace("{index}", itemsSelected.toString()).replace("{size}", _items.size.toString());
|
||||
(_fragment.topBar as ImportTopBarFragment?)?.setImportEnabled(true);
|
||||
} else {
|
||||
_textSelectDeselectAll.text = context.getString(R.string.select_all);
|
||||
|
|
|
@ -116,7 +116,7 @@ class ImportSubscriptionsFragment : MainFragment() {
|
|||
}.exceptionWithParameter<Throwable> { ex, para ->
|
||||
//setLoading(false);
|
||||
Logger.w(ChannelFragment.TAG, "Failed to load results.", ex);
|
||||
UIDialogs.toast(context, "Failed to fetch\n${para}", false)
|
||||
UIDialogs.toast(context, context.getString(R.string.failed_to_fetch) + "\n${para}", false)
|
||||
//UIDialogs.showDataRetryDialog(layoutInflater, { load(); });
|
||||
loadNext();
|
||||
};
|
||||
|
@ -147,14 +147,14 @@ class ImportSubscriptionsFragment : MainFragment() {
|
|||
|
||||
val tb = _fragment.topBar as ImportTopBarFragment?;
|
||||
tb?.let {
|
||||
it.title = "Import Subscriptions";
|
||||
it.title = context.getString(R.string.import_subscriptions);
|
||||
it.onImport.subscribe(this) {
|
||||
val subscriptionsToImport = _items.filter { i -> i.selected }.toList();
|
||||
for (subscriptionToImport in subscriptionsToImport) {
|
||||
StateSubscriptions.instance.addSubscription(subscriptionToImport.channel);
|
||||
}
|
||||
|
||||
UIDialogs.toast("${subscriptionsToImport.size} subscriptions imported.");
|
||||
UIDialogs.toast("${subscriptionsToImport.size} " + context.getString(R.string.subscriptions_imported));
|
||||
_fragment.closeSegment();
|
||||
};
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ class ImportSubscriptionsFragment : MainFragment() {
|
|||
if (_counter >= MAXIMUM_BATCH_SIZE) {
|
||||
if (!_limitToastShown) {
|
||||
_limitToastShown = true;
|
||||
UIDialogs.toast(context, "Stopped after $MAXIMUM_BATCH_SIZE to avoid rate limit, re-enter to import rest");
|
||||
UIDialogs.toast(context, "Stopped after {requestCount} to avoid rate limit, re-enter to import rest".replace("{requestCount}", MAXIMUM_BATCH_SIZE.toString()));
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
|
@ -187,7 +187,7 @@ class ImportSubscriptionsFragment : MainFragment() {
|
|||
val itemsSelected = _items.count { i -> i.selected };
|
||||
if (itemsSelected > 0) {
|
||||
_textSelectDeselectAll.text = context.getString(R.string.deselect_all);
|
||||
_textCounter.text = "$itemsSelected out of ${_items.size} selected";
|
||||
_textCounter.text = context.getString(R.string.index_out_of_size_selected).replace("{index}", itemsSelected.toString()).replace("{size}", _items.size.toString());
|
||||
(_fragment.topBar as ImportTopBarFragment?)?.setImportEnabled(true);
|
||||
} else {
|
||||
_textSelectDeselectAll.text = context.getString(R.string.select_all);
|
||||
|
|
|
@ -80,8 +80,8 @@ class PlaylistFragment : MainFragment() {
|
|||
constructor(fragment: PlaylistFragment, inflater: LayoutInflater) : super(inflater) {
|
||||
_fragment = fragment;
|
||||
|
||||
val nameInput = SlideUpMenuTextInput(context, "Name");
|
||||
val editPlaylistOverlay = SlideUpMenuOverlay(context, overlayContainer, "Edit playlist", "Ok", false, nameInput);
|
||||
val nameInput = SlideUpMenuTextInput(context, context.getString(R.string.name));
|
||||
val editPlaylistOverlay = SlideUpMenuOverlay(context, overlayContainer, context.getString(R.string.edit_playlist), context.getString(R.string.ok), false, nameInput);
|
||||
|
||||
_buttonDownload.visibility = View.VISIBLE;
|
||||
editPlaylistOverlay.onOK.subscribe {
|
||||
|
@ -113,14 +113,14 @@ class PlaylistFragment : MainFragment() {
|
|||
val playlist = _playlist ?: return@setOnShare;
|
||||
val reconstruction = StatePlaylists.instance.playlistStore.getReconstructionString(playlist);
|
||||
|
||||
UISlideOverlays.showOverlay(overlayContainer, "Playlist [${playlist.name}]", null, {},
|
||||
SlideUpMenuItem(context, R.drawable.ic_list, "Share as Text", "Share as a list of video urls", 1, {
|
||||
UISlideOverlays.showOverlay(overlayContainer, context.getString(R.string.playlist) + " [${playlist.name}]", null, {},
|
||||
SlideUpMenuItem(context, R.drawable.ic_list, context.getString(R.string.share_as_text), context.getString(R.string.share_as_a_list_of_video_urls), 1, {
|
||||
_fragment.startActivity(ShareCompat.IntentBuilder(context)
|
||||
.setType("text/plain")
|
||||
.setText(reconstruction)
|
||||
.intent);
|
||||
}),
|
||||
SlideUpMenuItem(context, R.drawable.ic_move_up, "Share as Import", "Share as a import file for Grayjay", 2, {
|
||||
SlideUpMenuItem(context, R.drawable.ic_move_up, context.getString(R.string.share_as_import), context.getString(R.string.share_as_a_import_file_for_grayjay), 2, {
|
||||
val shareUri = StatePlaylists.instance.createPlaylistShareJsonUri(context, playlist);
|
||||
_fragment.startActivity(ShareCompat.IntentBuilder(context)
|
||||
.setType("application/json")
|
||||
|
@ -146,7 +146,7 @@ class PlaylistFragment : MainFragment() {
|
|||
.exception<Throwable> {
|
||||
Logger.w(TAG, "Failed to load playlist.", it);
|
||||
val c = context ?: return@exception;
|
||||
UIDialogs.showGeneralRetryErrorDialog(c, "Failed to load playlist", it, ::fetchPlaylist);
|
||||
UIDialogs.showGeneralRetryErrorDialog(c, context.getString(R.string.failed_to_load_playlist), it, ::fetchPlaylist);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ class PlaylistFragment : MainFragment() {
|
|||
_fragment.topBar?.assume<NavigationTopBarFragment>()?.setMenuItems(arrayListOf(Pair(R.drawable.ic_copy) {
|
||||
val remotePlaylist = _remotePlaylist;
|
||||
if (remotePlaylist == null) {
|
||||
UIDialogs.toast("Please wait for playlist to finish loading");
|
||||
UIDialogs.toast(context.getString(R.string.please_wait_for_playlist_to_finish_loading));
|
||||
return@Pair;
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ class PlaylistFragment : MainFragment() {
|
|||
|
||||
withContext(Dispatchers.Main) {
|
||||
setLoading(false);
|
||||
UIDialogs.toast("Playlist copied as local playlist");
|
||||
UIDialogs.toast(context.getString(R.string.playlist_copied_as_local_playlist));
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
|
@ -284,7 +284,7 @@ class PlaylistFragment : MainFragment() {
|
|||
_buttonDownload.setImageResource(R.drawable.ic_loader_animated);
|
||||
_buttonDownload.drawable.assume<Animatable, Unit> { it.start() };
|
||||
_buttonDownload.setOnClickListener {
|
||||
UIDialogs.showConfirmationDialog(context, "Are you sure you want to delete the downloaded videos?", {
|
||||
UIDialogs.showConfirmationDialog(context, context.getString(R.string.are_you_sure_you_want_to_delete_the_downloaded_videos), {
|
||||
StateDownloads.instance.deleteCachedPlaylist(playlist.id);
|
||||
});
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ class PlaylistFragment : MainFragment() {
|
|||
else if(isDownloaded) {
|
||||
_buttonDownload.setImageResource(R.drawable.ic_download_off);
|
||||
_buttonDownload.setOnClickListener {
|
||||
UIDialogs.showConfirmationDialog(context, "Are you sure you want to delete the downloaded videos?", {
|
||||
UIDialogs.showConfirmationDialog(context, context.getString(R.string.are_you_sure_you_want_to_delete_the_downloaded_videos), {
|
||||
StateDownloads.instance.deleteCachedPlaylist(playlist.id);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -92,8 +92,8 @@ class PlaylistsFragment : MainFragment() {
|
|||
recyclerPlaylists.adapter = _adapterPlaylist;
|
||||
recyclerPlaylists.layoutManager = LinearLayoutManager(context);
|
||||
|
||||
val nameInput = SlideUpMenuTextInput(context, "Name");
|
||||
val addPlaylistOverlay = SlideUpMenuOverlay(context, findViewById<FrameLayout>(R.id.overlay_create_playlist), "Create new playlist", "Ok", false, nameInput);
|
||||
val nameInput = SlideUpMenuTextInput(context, context.getString(R.string.name));
|
||||
val addPlaylistOverlay = SlideUpMenuOverlay(context, findViewById<FrameLayout>(R.id.overlay_create_playlist), context.getString(R.string.create_new_playlist), context.getString(R.string.ok), false, nameInput);
|
||||
|
||||
_adapterPlaylist.onClick.subscribe { p -> _fragment.navigate<PlaylistFragment>(p); };
|
||||
_adapterPlaylist.onPlay.subscribe { p ->
|
||||
|
@ -130,7 +130,7 @@ class PlaylistsFragment : MainFragment() {
|
|||
_appBar = findViewById(R.id.app_bar);
|
||||
_layoutWatchlist = findViewById(R.id.layout_watchlist);
|
||||
|
||||
findViewById<TextView>(R.id.text_view_all).setOnClickListener { _fragment.navigate<WatchLaterFragment>("Watch Later"); };
|
||||
findViewById<TextView>(R.id.text_view_all).setOnClickListener { _fragment.navigate<WatchLaterFragment>(context.getString(R.string.watch_later)); };
|
||||
StatePlaylists.instance.onWatchLaterChanged.subscribe(this) {
|
||||
updateWatchLater();
|
||||
};
|
||||
|
|
|
@ -154,13 +154,13 @@ class PostDetailFragment : MainFragment {
|
|||
{
|
||||
val result = StatePlatform.instance.getContentDetails(it).await();
|
||||
if(result !is IPlatformPostDetails)
|
||||
throw IllegalStateException("Expected media content, found ${result.contentType}");
|
||||
throw IllegalStateException(context.getString(R.string.expected_media_content_found) + " ${result.contentType}");
|
||||
return@TaskHandler result;
|
||||
})
|
||||
.success { setPostDetails(it) }
|
||||
.exception<Throwable> {
|
||||
Logger.w(ChannelFragment.TAG, "Failed to load post.", it);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to load post", it, ::fetchPost);
|
||||
Logger.w(ChannelFragment.TAG, context.getString(R.string.failed_to_load_post), it);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_post), it, ::fetchPost);
|
||||
} else TaskHandler(IPlatformPostDetails::class.java) { _fragment.lifecycleScope };
|
||||
|
||||
private val _taskLoadPolycentricProfile = TaskHandler<PlatformID, PolycentricCache.CachedPolycentricProfile?>(StateApp.instance.scopeGetter, { PolycentricCache.instance.getProfileAsync(it) })
|
||||
|
@ -222,7 +222,7 @@ class PostDetailFragment : MainFragment {
|
|||
val replyCount = c.replyCount ?: 0;
|
||||
var metadata = "";
|
||||
if (replyCount > 0) {
|
||||
metadata += "$replyCount replies";
|
||||
metadata += "$replyCount " + context.getString(R.string.replies);
|
||||
}
|
||||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
|
@ -601,7 +601,7 @@ class PostDetailFragment : MainFragment {
|
|||
val subscribers = value?.author?.subscribers;
|
||||
if(subscribers != null && subscribers > 0) {
|
||||
_channelMeta.visibility = View.VISIBLE;
|
||||
_channelMeta.text = if((value.author?.subscribers ?: 0) > 0) value.author.subscribers!!.toHumanNumber() + " subscribers" else "";
|
||||
_channelMeta.text = if((value.author.subscribers ?: 0) > 0) value.author.subscribers!!.toHumanNumber() + " " + context.getString(R.string.subscribers) else "";
|
||||
} else {
|
||||
_channelMeta.visibility = View.GONE;
|
||||
_channelMeta.text = "";
|
||||
|
|
|
@ -107,7 +107,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
StatePlugins.instance.setPluginSettings(id, _settings!!);
|
||||
reloadSource(id);
|
||||
|
||||
UIDialogs.toast("Plugin settings saved", false);
|
||||
UIDialogs.toast(context.getString(R.string.plugin_settings_saved), false);
|
||||
}
|
||||
if(_settingsAppChanged) {
|
||||
_settingsAppForm.setObjectValues();
|
||||
|
@ -144,8 +144,8 @@ class SourceDetailFragment : MainFragment() {
|
|||
try {
|
||||
_settings = settingValues;
|
||||
_settingsForm.fromPluginSettings(
|
||||
settings, settingValues, "Plugin settings",
|
||||
"These settings are defined by the plugin"
|
||||
settings, settingValues, context.getString(R.string.plugin_settings),
|
||||
context.getString(R.string.these_settings_are_defined_by_the_plugin)
|
||||
);
|
||||
_settingsForm.onChanged.clear();
|
||||
_settingsForm.onChanged.subscribe { field, value ->
|
||||
|
@ -158,7 +158,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to load source", ex);
|
||||
UIDialogs.toast("Failed to loast source");
|
||||
UIDialogs.toast(context.getString(R.string.failed_to_load_source));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,8 +204,8 @@ class SourceDetailFragment : MainFragment() {
|
|||
val isEnabled = StatePlatform.instance.isClientEnabled(source);
|
||||
|
||||
groups.add(
|
||||
BigButtonGroup(c, "Update",
|
||||
BigButton(c, "Check for updates", "Checks for new versions of the source", R.drawable.ic_update) {
|
||||
BigButtonGroup(c, context.getString(R.string.update),
|
||||
BigButton(c, context.getString(R.string.check_for_updates), context.getString(R.string.checks_for_new_versions_of_the_source), R.drawable.ic_update) {
|
||||
checkForUpdatesSource();
|
||||
}
|
||||
)
|
||||
|
@ -213,8 +213,8 @@ class SourceDetailFragment : MainFragment() {
|
|||
|
||||
if (source.isLoggedIn) {
|
||||
groups.add(
|
||||
BigButtonGroup(c, "Authentication",
|
||||
BigButton(c, "Logout", "Sign out of the platform", R.drawable.ic_logout) {
|
||||
BigButtonGroup(c, context.getString(R.string.authentication),
|
||||
BigButton(c, context.getString(R.string.logout), context.getString(R.string.sign_out_of_the_platform), R.drawable.ic_logout) {
|
||||
logoutSource();
|
||||
}
|
||||
)
|
||||
|
@ -223,7 +223,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
val migrationButtons = mutableListOf<BigButton>();
|
||||
if (isEnabled && source.capabilities.hasGetUserSubscriptions) {
|
||||
migrationButtons.add(
|
||||
BigButton(c, "Import Subscriptions", "Import your subscriptions from this source", R.drawable.ic_subscriptions) {
|
||||
BigButton(c, context.getString(R.string.import_subscriptions), context.getString(R.string.import_your_subscriptions_from_this_source), R.drawable.ic_subscriptions) {
|
||||
Logger.i(TAG, "Import subscriptions clicked.");
|
||||
importSubscriptionsSource();
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
}
|
||||
|
||||
if (isEnabled && source.capabilities.hasGetUserPlaylists && source.capabilities.hasGetPlaylist) {
|
||||
val bigButton = BigButton(c, "Import Playlists", "Import your playlists from this source", R.drawable.ic_playlist) {
|
||||
val bigButton = BigButton(c, context.getString(R.string.import_playlists), context.getString(R.string.import_your_playlists_from_this_source), R.drawable.ic_playlist) {
|
||||
Logger.i(TAG, "Import playlists clicked.");
|
||||
importPlaylistsSource();
|
||||
};
|
||||
|
@ -244,13 +244,13 @@ class SourceDetailFragment : MainFragment() {
|
|||
}
|
||||
|
||||
if (migrationButtons.size > 0) {
|
||||
groups.add(BigButtonGroup(c, "Migration", *migrationButtons.toTypedArray()));
|
||||
groups.add(BigButtonGroup(c, context.getString(R.string.migration), *migrationButtons.toTypedArray()));
|
||||
}
|
||||
} else {
|
||||
if(config.authentication != null) {
|
||||
groups.add(
|
||||
BigButtonGroup(c, "Authentication",
|
||||
BigButton(c, "Login", "Sign into the platform of this source", R.drawable.ic_login) {
|
||||
BigButtonGroup(c, context.getString(R.string.authentication),
|
||||
BigButton(c, context.getString(R.string.login), context.getString(R.string.sign_into_the_platform_of_this_source), R.drawable.ic_login) {
|
||||
loginSource();
|
||||
}
|
||||
)
|
||||
|
@ -260,8 +260,8 @@ class SourceDetailFragment : MainFragment() {
|
|||
|
||||
val clientIfExists = StatePlugins.instance.getPlugin(config.id);
|
||||
groups.add(
|
||||
BigButtonGroup(c, "Management",
|
||||
BigButton(c, "Uninstall", "Removes the plugin from the app", R.drawable.ic_block) {
|
||||
BigButtonGroup(c, context.getString(R.string.management),
|
||||
BigButton(c, context.getString(R.string.uninstall), context.getString(R.string.removes_the_plugin_from_the_app), R.drawable.ic_block) {
|
||||
uninstallSource();
|
||||
}.withBackground(R.drawable.background_big_button_red).apply {
|
||||
this.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
|
@ -269,8 +269,8 @@ class SourceDetailFragment : MainFragment() {
|
|||
};
|
||||
},
|
||||
if(clientIfExists?.captchaEncrypted != null)
|
||||
BigButton(c, "Delete Captcha", "Deletes stored captcha answer for this plugin", R.drawable.ic_block) {
|
||||
clientIfExists?.updateCaptcha(null);
|
||||
BigButton(c, context.getString(R.string.delete_captcha), context.getString(R.string.deletes_stored_captcha_answer_for_this_plugin), R.drawable.ic_block) {
|
||||
clientIfExists.updateCaptcha(null);
|
||||
}.apply {
|
||||
this.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
setMargins(0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, resources.displayMetrics).toInt(), 0, 0);
|
||||
|
@ -329,7 +329,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
}
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
context?.let { UIDialogs.showGeneralErrorDialog(it, "Failed to retrieve playlists.", e) }
|
||||
context?.let { UIDialogs.showGeneralErrorDialog(it, it.getString(R.string.failed_to_retrieve_playlists), e) }
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
@ -354,14 +354,14 @@ class SourceDetailFragment : MainFragment() {
|
|||
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val subscriptions = source.getUserSubscriptions().distinct();
|
||||
Logger.i(TAG, "${subscriptions.size} user subscriptions retrieved.");
|
||||
Logger.i(TAG, context.getString(R.string.subscriptioncount_user_subscriptions_retrieved).replace("{subscriptionCount}", subscriptions.size.toString()));
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
fragment.navigate<ImportSubscriptionsFragment>(subscriptions);
|
||||
}
|
||||
} catch(e: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
context?.let { UIDialogs.showGeneralErrorDialog(it, "Failed to retrieve subscriptions.", e) }
|
||||
context?.let { UIDialogs.showGeneralErrorDialog(it, context.getString(R.string.failed_to_retrieve_subscriptions), e) }
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
@ -375,7 +375,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
val config = _config ?: return;
|
||||
val source = StatePlatform.instance.getClient(config.id);
|
||||
|
||||
UIDialogs.showConfirmationDialog(context, "Are you sure you want to uninstall ${source.name}", {
|
||||
UIDialogs.showConfirmationDialog(context, context.getString(R.string.are_you_sure_you_want_to_uninstall) + " ${source.name}", {
|
||||
StatePlugins.instance.deletePlugin(source.id);
|
||||
|
||||
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||
|
@ -386,7 +386,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(context, "Uninstalled ${source.name}");
|
||||
UIDialogs.toast(context, context.getString(R.string.uninstalled) + " ${source.name}");
|
||||
fragment.closeSegment();
|
||||
}
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
|
||||
if (!response.isOk || response.body == null) {
|
||||
Logger.w(TAG, "Failed to check for updates (sourceUrl=${sourceUrl}, response.isOk=${response.isOk}, response.body=${response.body}).");
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast("Failed to check for updates"); };
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast(context.getString(R.string.failed_to_check_for_updates)); };
|
||||
return@launch;
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
val config = SourcePluginConfig.fromJson(configJson);
|
||||
if (config.version <= c.version) {
|
||||
Logger.i(TAG, "Plugin is up to date.");
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast("Plugin is fully up to date"); };
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast(context.getString(R.string.plugin_is_fully_up_to_date)); };
|
||||
return@launch;
|
||||
}
|
||||
|
||||
|
@ -430,7 +430,7 @@ class SourceDetailFragment : MainFragment() {
|
|||
Logger.i(TAG, "Started add source activity.");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to check for updates.", e);
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast("Failed to check for updates"); };
|
||||
withContext(Dispatchers.Main) { UIDialogs.toast(context.getString(R.string.failed_to_check_for_updates)); };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,9 +195,8 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showDialog(context, R.drawable.ic_security_pred,
|
||||
"Rate Limit Warning", "This is a temporary measure to prevent people from hitting rate limit until we have better support for lots of subscriptions." +
|
||||
"\n\nYou have too many subscriptions for the following plugins:\n",
|
||||
subsByLimited.map { "${it.first.config.name}: ${it.second.size} Subscriptions" } .joinToString("\n"), 0, UIDialogs.Action("Refresh Anyway", {
|
||||
context.getString(R.string.rate_limit_warning), context.getString(R.string.this_is_a_temporary_measure_to_prevent_people_from_hitting_rate_limit_until_we_have_better_support_for_lots_of_subscriptions) + context.getString(R.string.you_have_too_many_subscriptions_for_the_following_plugins),
|
||||
subsByLimited.map { it.first.config.name + ": " + it.second.size + " " + context.getString(R.string.subscriptions) } .joinToString("\n"), 0, UIDialogs.Action("Refresh Anyway", {
|
||||
_bypassRateLimit = true;
|
||||
loadResults();
|
||||
}, UIDialogs.ActionStyle.DANGEROUS_TEXT),
|
||||
|
@ -226,10 +225,10 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
|
||||
synchronized(_filterLock) {
|
||||
_subscriptionBar?.setToggles(
|
||||
SubscriptionBar.Toggle("Videos", _filterSettings.allowContentTypes.contains(ContentType.MEDIA)) { toggleFilterContentTypes(listOf(ContentType.MEDIA, ContentType.NESTED_VIDEO), it); },
|
||||
SubscriptionBar.Toggle("Posts", _filterSettings.allowContentTypes.contains(ContentType.POST)) { toggleFilterContentType(ContentType.POST, it); },
|
||||
SubscriptionBar.Toggle("Live", _filterSettings.allowLive) { _filterSettings.allowLive = it; _filterSettings.save(); loadResults(false); },
|
||||
SubscriptionBar.Toggle("Planned", _filterSettings.allowPlanned) { _filterSettings.allowPlanned = it; _filterSettings.save(); loadResults(false); }
|
||||
SubscriptionBar.Toggle(context.getString(R.string.videos), _filterSettings.allowContentTypes.contains(ContentType.MEDIA)) { toggleFilterContentTypes(listOf(ContentType.MEDIA, ContentType.NESTED_VIDEO), it); },
|
||||
SubscriptionBar.Toggle(context.getString(R.string.posts), _filterSettings.allowContentTypes.contains(ContentType.POST)) { toggleFilterContentType(ContentType.POST, it); },
|
||||
SubscriptionBar.Toggle(context.getString(R.string.live), _filterSettings.allowLive) { _filterSettings.allowLive = it; _filterSettings.save(); loadResults(false); },
|
||||
SubscriptionBar.Toggle(context.getString(R.string.planned), _filterSettings.allowPlanned) { _filterSettings.allowPlanned = it; _filterSettings.save(); loadResults(false); }
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -283,7 +282,7 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
val cachePager = ChannelContentCache.instance.getSubscriptionCachePager();
|
||||
val results = cachePager.getResults();
|
||||
Logger.i(TAG, "Subscription show cache (${results.size})");
|
||||
setTextCentered(if (results.isEmpty()) "No results found\nSwipe down to refresh" else null);
|
||||
setTextCentered(if (results.isEmpty()) context.getString(R.string.no_results_found_swipe_down_to_refresh) else null);
|
||||
setPager(cachePager);
|
||||
} else {
|
||||
setTextCentered(null);
|
||||
|
@ -299,7 +298,7 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
finishRefreshLayoutLoader();
|
||||
setLoading(false);
|
||||
setPager(pager);
|
||||
setTextCentered(if (pager.getResults().isEmpty()) "No results found\nSwipe down to refresh" else null);
|
||||
setTextCentered(if (pager.getResults().isEmpty()) context.getString(R.string.no_results_found_swipe_down_to_refresh) else null);
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to finish loading", e)
|
||||
}
|
||||
|
@ -326,7 +325,7 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
if (toShow is PluginException)
|
||||
UIDialogs.toast(
|
||||
it,
|
||||
"Plugin [${toShow.config.name}] (${channel}) failed:\n${toShow.message}"
|
||||
context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", toShow.config.name).replace("{message}", toShow.message ?: "")
|
||||
);
|
||||
else
|
||||
UIDialogs.toast(it, ex.message ?: "");
|
||||
|
@ -340,7 +339,7 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
.map { it!! }
|
||||
.toList();
|
||||
for(distinctPluginFail in failedPlugins)
|
||||
UIDialogs.toast(it, "Plugin [${distinctPluginFail.config.name}] failed:\n${distinctPluginFail.message}");
|
||||
UIDialogs.toast(it, context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", distinctPluginFail.config.name).replace("{message}", distinctPluginFail.message ?: ""));
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to handle exceptions", e)
|
||||
|
|
|
@ -541,7 +541,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
val replyCount = c.replyCount ?: 0;
|
||||
var metadata = "";
|
||||
if (replyCount > 0) {
|
||||
metadata += "$replyCount replies";
|
||||
metadata += "$replyCount " + context.getString(R.string.replies);
|
||||
}
|
||||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
|
@ -579,13 +579,13 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
|
||||
fun updateMoreButtons() {
|
||||
val buttons = listOf(RoundButton(context, R.drawable.ic_add, "Add", TAG_ADD) {
|
||||
val buttons = listOf(RoundButton(context, R.drawable.ic_add, context.getString(R.string.add), TAG_ADD) {
|
||||
(video ?: _searchVideo)?.let {
|
||||
_slideUpOverlay = UISlideOverlays.showAddToOverlay(it, _overlayContainer);
|
||||
}
|
||||
},
|
||||
if(video?.isLive ?: false)
|
||||
RoundButton(context, R.drawable.ic_chat, "Live Chat", TAG_LIVECHAT) {
|
||||
RoundButton(context, R.drawable.ic_chat, context.getString(R.string.live_chat), TAG_LIVECHAT) {
|
||||
video?.let {
|
||||
try {
|
||||
loadLiveChat(it);
|
||||
|
@ -595,7 +595,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
}
|
||||
} else null,
|
||||
RoundButton(context, R.drawable.ic_screen_share, "Background", TAG_BACKGROUND) {
|
||||
RoundButton(context, R.drawable.ic_screen_share, context.getString(R.string.background), TAG_BACKGROUND) {
|
||||
if(!allowBackground) {
|
||||
_player.switchToAudioMode();
|
||||
allowBackground = true;
|
||||
|
@ -607,31 +607,31 @@ class VideoDetailView : ConstraintLayout {
|
|||
it.text.text = resources.getString(R.string.background);
|
||||
}
|
||||
},
|
||||
RoundButton(context, R.drawable.ic_download, "Download", TAG_DOWNLOAD) {
|
||||
RoundButton(context, R.drawable.ic_download, context.getString(R.string.download), TAG_DOWNLOAD) {
|
||||
video?.let {
|
||||
_slideUpOverlay = UISlideOverlays.showDownloadVideoOverlay(it, _overlayContainer, context.contentResolver);
|
||||
};
|
||||
},
|
||||
RoundButton(context, R.drawable.ic_share, "Share", TAG_SHARE) {
|
||||
RoundButton(context, R.drawable.ic_share, context.getString(R.string.share), TAG_SHARE) {
|
||||
video?.let {
|
||||
Logger.i(TAG, "Share preventPictureInPicture = true");
|
||||
preventPictureInPicture = true;
|
||||
shareVideo();
|
||||
};
|
||||
},
|
||||
RoundButton(context, R.drawable.ic_screen_share, "Overlay", TAG_OVERLAY) {
|
||||
RoundButton(context, R.drawable.ic_screen_share, context.getString(R.string.overlay), TAG_OVERLAY) {
|
||||
this.startPictureInPicture();
|
||||
fragment.forcePictureInPicture();
|
||||
//PiPActivity.startPiP(context);
|
||||
},
|
||||
RoundButton(context, R.drawable.ic_export, "Page", TAG_OPEN) {
|
||||
RoundButton(context, R.drawable.ic_export, context.getString(R.string.page), TAG_OPEN) {
|
||||
video?.let {
|
||||
val url = video?.shareUrl ?: _searchVideo?.shareUrl ?: _url;
|
||||
fragment.navigate<BrowserFragment>(url);
|
||||
fragment.minimizeVideoDetail();
|
||||
};
|
||||
},
|
||||
RoundButton(context, R.drawable.ic_refresh, "Reload", "Reload") {
|
||||
RoundButton(context, R.drawable.ic_refresh, context.getString(R.string.reload), "Reload") {
|
||||
reloadVideo();
|
||||
}).filterNotNull();
|
||||
if(!_buttonPinStore.getAllValues().any())
|
||||
|
@ -857,7 +857,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
val subTitleSegments : ArrayList<String> = ArrayList();
|
||||
if(video.viewCount > 0)
|
||||
subTitleSegments.add("${video.viewCount.toHumanNumber()} ${if(video.isLive) "watching now" else "views"}");
|
||||
subTitleSegments.add("${video.viewCount.toHumanNumber()} ${if(video.isLive) context.getString(R.string.watching_now) else context.getString(R.string.views)}");
|
||||
if(video.datetime != null) {
|
||||
val diff = video.datetime?.getNowDiffSeconds() ?: 0;
|
||||
val ago = video.datetime?.toHumanNowDiffString(true)
|
||||
|
@ -873,7 +873,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_subTitle.text = subTitleSegments.joinToString(" • ");
|
||||
_playWhenReady = true;
|
||||
if(video.author.subscribers != null) {
|
||||
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " subscribers" else "";
|
||||
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " " + context.getString(R.string.subscribers)else "";
|
||||
(_channelName.layoutParams as MarginLayoutParams).setMargins(0, (DP_5 * -1).toInt(), 0, 0);
|
||||
} else {
|
||||
_channelMeta.text = "";
|
||||
|
@ -933,7 +933,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
|
||||
if(videoDetail.datetime != null && videoDetail.datetime!! > OffsetDateTime.now())
|
||||
UIDialogs.toast(context, "Planned in ${videoDetail.datetime?.toHumanNowDiffString(true)}")
|
||||
UIDialogs.toast(context, context.getString(R.string.planned_in) + " ${videoDetail.datetime?.toHumanNowDiffString(true)}")
|
||||
|
||||
if (!videoDetail.isLive) {
|
||||
_player.setPlaybackRate(Settings.instance.playback.getDefaultPlaybackSpeed());
|
||||
|
@ -965,7 +965,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
catch(ex: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to get Playback Tracker", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_get_playback_tracker), ex);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -983,7 +983,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_title.text = video.name;
|
||||
_channelName.text = video.author.name;
|
||||
if(video.author.subscribers != null) {
|
||||
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " subscribers" else "";
|
||||
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " " + context.getString(R.string.subscribers) else "";
|
||||
(_channelName.layoutParams as MarginLayoutParams).setMargins(0, (DP_5 * -1).toInt(), 0, 0);
|
||||
} else {
|
||||
_channelMeta.text = "";
|
||||
|
@ -1008,7 +1008,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_platform.setPlatformFromClientID(video.id.pluginId);
|
||||
val subTitleSegments : ArrayList<String> = ArrayList();
|
||||
if(video.viewCount > 0)
|
||||
subTitleSegments.add("${video.viewCount.toHumanNumber()} ${if(video.isLive) "watching now" else "views"}");
|
||||
subTitleSegments.add("${video.viewCount.toHumanNumber()} ${if(video.isLive) context.getString(R.string.watching_now) else context.getString(R.string.views)}");
|
||||
if(video.datetime != null) {
|
||||
val diff = video.datetime?.getNowDiffSeconds() ?: 0;
|
||||
val ago = video.datetime?.toHumanNowDiffString(true)
|
||||
|
@ -1167,7 +1167,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
livePager = StatePlatform.instance.getLiveEvents(video.url);
|
||||
} catch (ex: Throwable) {
|
||||
livePager = null;
|
||||
UIDialogs.toast("Exception retrieving live events:\n" + ex.message);
|
||||
UIDialogs.toast(context.getString(R.string.exception_retrieving_live_events) + "\n" + ex.message);
|
||||
Logger.e(TAG, "Failed to retrieve live chat events", ex);
|
||||
}
|
||||
try {
|
||||
|
@ -1178,7 +1178,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
catch(ex: Throwable) {
|
||||
liveChatWindow = null;
|
||||
UIDialogs.toast("Exception retrieving live chat window:\n" + ex.message);
|
||||
UIDialogs.toast(context.getString(R.string.exception_retrieving_live_chat_window) + "\n" + ex.message);
|
||||
Logger.e(TAG, "Failed to retrieve live chat window", ex);
|
||||
}
|
||||
val liveChat = livePager?.let {
|
||||
|
@ -1200,7 +1200,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to load live chat", ex);
|
||||
|
||||
UIDialogs.toast("Live chat failed to load\n" + ex.message);
|
||||
UIDialogs.toast(context.getString(R.string.live_chat_failed_to_load) + "\n" + ex.message);
|
||||
//_liveChat?.handleEvents(listOf(LiveEventComment("SYSTEM", null, "Failed to load live chat:\n" + ex.message, "#FF0000")))
|
||||
/*
|
||||
fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||
|
@ -1257,11 +1257,11 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
catch(ex: UnsupportedCastException) {
|
||||
Logger.e(TAG, "Failed to load cast media", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, "Unsupported Cast format", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.unsupported_cast_format), ex);
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to load media", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to load media", ex);
|
||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_load_media), ex);
|
||||
}
|
||||
}
|
||||
private fun loadCurrentVideoCast(video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, resumePositionMs: Long) {
|
||||
|
@ -1279,7 +1279,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
Logger.i(TAG, "onSourceChanged(videoSource=$videoSource, audioSource=$audioSource, resume=$resume)")
|
||||
|
||||
if((videoSource == null || videoSource is LocalVideoSource) && (audioSource == null || audioSource is LocalAudioSource))
|
||||
UIDialogs.toast(context, "Offline Playback", false);
|
||||
UIDialogs.toast(context, context.getString(R.string.offline_playback), false);
|
||||
//If LiveStream, set to end
|
||||
if(videoSource is IDashManifestSource || videoSource is IHLSManifestSource) {
|
||||
if (video?.isLive == true) {
|
||||
|
@ -1320,12 +1320,12 @@ class VideoDetailView : ConstraintLayout {
|
|||
_didTriggerDatasourceError = true;
|
||||
|
||||
UIDialogs.showDialog(context, R.drawable.ic_error_pred,
|
||||
"Media Error",
|
||||
"The media source encountered an unauthorized error.\nThis might be solved by a plugin reload.\nWould you like to reload?\n(Experimental)",
|
||||
context.getString(R.string.media_error),
|
||||
context.getString(R.string.the_media_source_encountered_an_unauthorized_error_this_might_be_solved_by_a_plugin_reload_would_you_like_to_reload_experimental),
|
||||
null,
|
||||
0,
|
||||
UIDialogs.Action("No", { _didTriggerDatasourceError = false }),
|
||||
UIDialogs.Action("Yes", {
|
||||
UIDialogs.Action(context.getString(R.string.no), { _didTriggerDatasourceError = false }),
|
||||
UIDialogs.Action(context.getString(R.string.yes), {
|
||||
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
StatePlatform.instance.reloadClient(context, config.id);
|
||||
|
@ -1423,8 +1423,9 @@ class VideoDetailView : ConstraintLayout {
|
|||
?.filter { it.container == bestAudioContainer }
|
||||
?.toList() ?: listOf();
|
||||
|
||||
_overlay_quality_selector = SlideUpMenuOverlay(this.context, _overlay_quality_container, "Quality", null, true,
|
||||
if (!_isCasting) SlideUpMenuTitle(this.context).apply { setTitle("Playback Rate") } else null,
|
||||
_overlay_quality_selector = SlideUpMenuOverlay(this.context, _overlay_quality_container, context.getString(
|
||||
R.string.quality), null, true,
|
||||
if (!_isCasting) SlideUpMenuTitle(this.context).apply { setTitle(context.getString(R.string.playback_rate)) } else null,
|
||||
if (!_isCasting) SlideUpMenuButtonList(this.context).apply {
|
||||
setButtons(listOf("0.25", "0.5", "0.75", "1.0", "1.25", "1.5", "1.75", "2.0", "2.25"), _player.getPlaybackRate().toString());
|
||||
onClick.subscribe { v ->
|
||||
|
@ -1438,7 +1439,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
} else null,
|
||||
|
||||
if(localVideoSources?.isNotEmpty() == true)
|
||||
SlideUpMenuGroup(this.context, "Offline Video", "video",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.offline_video), "video",
|
||||
*localVideoSources.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, "${it.width}x${it.height}", it,
|
||||
|
@ -1446,7 +1447,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(localAudioSource?.isNotEmpty() == true)
|
||||
SlideUpMenuGroup(this.context, "Offline Audio", "audio",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.offline_audio), "audio",
|
||||
*localAudioSource.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
||||
|
@ -1454,7 +1455,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(localSubtitleSources?.isNotEmpty() == true)
|
||||
SlideUpMenuGroup(this.context, "Offline Subtitles", "subtitles",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.offline_subtitles), "subtitles",
|
||||
*localSubtitleSources
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_edit, it.name, "", it,
|
||||
|
@ -1462,7 +1463,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(liveStreamVideoFormats?.isEmpty() == false)
|
||||
SlideUpMenuGroup(this.context, "Stream Video", "video",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.stream_video), "video",
|
||||
*liveStreamVideoFormats.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it?.label ?: it.containerMimeType ?: it.bitrate.toString(), "${it.width}x${it.height}", it,
|
||||
|
@ -1470,7 +1471,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(liveStreamAudioFormats?.isEmpty() == false)
|
||||
SlideUpMenuGroup(this.context, "Stream Audio", "audio",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio",
|
||||
*liveStreamAudioFormats.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_music, "${it?.label ?: it.containerMimeType} ${it.bitrate}", "", it,
|
||||
|
@ -1479,7 +1480,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
else null,
|
||||
|
||||
if(bestVideoSources.isNotEmpty())
|
||||
SlideUpMenuGroup(this.context, "Video", "video",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.video), "video",
|
||||
*bestVideoSources.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, if (it.width > 0 && it.height > 0) "${it.width}x${it.height}" else "", it,
|
||||
|
@ -1487,7 +1488,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(bestAudioSources.isNotEmpty())
|
||||
SlideUpMenuGroup(this.context, "Audio", "audio",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.audio), "audio",
|
||||
*bestAudioSources.stream()
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
||||
|
@ -1495,7 +1496,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}.toList().toTypedArray())
|
||||
else null,
|
||||
if(video?.subtitles?.isNotEmpty() ?: false && video != null)
|
||||
SlideUpMenuGroup(this.context, "Subtitles", "subtitles",
|
||||
SlideUpMenuGroup(this.context, context.getString(R.string.subtitles), "subtitles",
|
||||
*video.subtitles
|
||||
.map {
|
||||
SlideUpMenuItem(this.context, R.drawable.ic_edit, it.name, "", it,
|
||||
|
@ -1618,12 +1619,13 @@ class VideoDetailView : ConstraintLayout {
|
|||
private fun handleUnavailableVideo(msg: String? = null) {
|
||||
if (!nextVideo()) {
|
||||
if(video?.datetime == null || video?.datetime!! < OffsetDateTime.now().minusHours(1))
|
||||
UIDialogs.showDialog(context, R.drawable.ic_lock, "Unavailable video", msg ?: "This video is unavailable.", null, 0,
|
||||
UIDialogs.Action("Back", {
|
||||
UIDialogs.showDialog(context, R.drawable.ic_lock, context.getString(R.string.unavailable_video), msg ?: context.getString(R.string.this_video_is_unavailable), null, 0,
|
||||
UIDialogs.Action(context.getString(R.string.back), {
|
||||
this@VideoDetailView.onClose.emit();
|
||||
}, UIDialogs.ActionStyle.PRIMARY));
|
||||
}, UIDialogs.ActionStyle.PRIMARY)
|
||||
);
|
||||
} else {
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_UNAVAILABLE", "Unavailable video", "There was an unavailable video in your queue [${video?.name}] by [${video?.author?.name}].", AnnouncementType.SESSION)
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_UNAVAILABLE", context.getString(R.string.unavailable_video), context.getString(R.string.there_was_an_unavailable_video_in_your_queue_videoname_by_authorname).replace("{videoName}", video?.name ?: "").replace("{authorName}", video?.author?.name ?: ""), AnnouncementType.SESSION)
|
||||
}
|
||||
|
||||
video?.let { StatePlatform.instance.clearContentDetailCache(it.url) };
|
||||
|
@ -1875,9 +1877,9 @@ class VideoDetailView : ConstraintLayout {
|
|||
_player.getGlobalVisibleRect(r);
|
||||
r.right = r.right - _player.paddingEnd;
|
||||
val playpauseAction = if(_player.playing)
|
||||
RemoteAction(Icon.createWithResource(context, R.drawable.ic_pause_notif), "Pause", "Pauses the video", MediaControlReceiver.getPauseIntent(context, 5));
|
||||
RemoteAction(Icon.createWithResource(context, R.drawable.ic_pause_notif), context.getString(R.string.pause), context.getString(R.string.pauses_the_video), MediaControlReceiver.getPauseIntent(context, 5));
|
||||
else
|
||||
RemoteAction(Icon.createWithResource(context, R.drawable.ic_play_notif), "Play", "Resumes the video", MediaControlReceiver.getPlayIntent(context, 6));
|
||||
RemoteAction(Icon.createWithResource(context, R.drawable.ic_play_notif), context.getString(R.string.play), context.getString(R.string.resumes_the_video), MediaControlReceiver.getPlayIntent(context, 6));
|
||||
|
||||
return PictureInPictureParams.Builder()
|
||||
.setAspectRatio(Rational(videoSourceWidth, videoSourceHeight))
|
||||
|
@ -2066,7 +2068,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
}, UIDialogs.ActionStyle.PRIMARY)
|
||||
);
|
||||
} else {
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_NOSOURCES", "Video without source", "There was a in your queue [${video?.name}] by [${video?.author?.name}] without the required source being enabled, playback was skipped.", AnnouncementType.SESSION)
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_NOSOURCES", context.getString(R.string.video_without_source), context.getString(R.string.there_was_a_in_your_queue_videoname_by_authorname_without_the_required_source_being_enabled_playback_was_skipped).replace("{videoName}", video?.name ?: "").replace("{authorName}", video?.author?.name ?: ""), AnnouncementType.SESSION)
|
||||
}
|
||||
}
|
||||
.exception<ContentNotAvailableYetException> {
|
||||
|
@ -2085,9 +2087,10 @@ class VideoDetailView : ConstraintLayout {
|
|||
Logger.w(TAG, "exception<ScriptImplementationException>", it)
|
||||
|
||||
if (!nextVideo()) {
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to load video (ScriptImplementationException)", it, ::fetchVideo);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_video_scriptimplementationexception), it, ::fetchVideo);
|
||||
} else {
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_INVALIDVIDEO", "Invalid video", "There was an invalid video in your queue [${video?.name}] by [${video?.author?.name}], playback was skipped.", AnnouncementType.SESSION)
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_INVALIDVIDEO", context.getString(R.string.invalid_video), context.getString(
|
||||
R.string.there_was_an_invalid_video_in_your_queue_videoname_by_authorname_playback_was_skipped).replace("{videoName}", video?.name ?: "").replace("{authorName}", video?.author?.name ?: ""), AnnouncementType.SESSION)
|
||||
}
|
||||
}
|
||||
.exception<ScriptAgeException> {
|
||||
|
@ -2102,7 +2105,9 @@ class VideoDetailView : ConstraintLayout {
|
|||
this@VideoDetailView.onClose.emit();
|
||||
}, UIDialogs.ActionStyle.PRIMARY));
|
||||
} else {
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_AGERESTRICT", "Age restricted video", "There was an age restricted video in your queue [${video?.name}] by [${video?.author?.name}], this video was not accessible and playback was skipped.", AnnouncementType.SESSION)
|
||||
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_AGERESTRICT", context.getString(R.string.age_restricted_video),
|
||||
context.getString(R.string.there_was_an_age_restricted_video_in_your_queue_videoname_by_authorname_this_video_was_not_accessible_and_playback_was_skipped).replace("{videoName}", video?.name ?: "").replace("{authorName}", video?.author?.name ?: ""),
|
||||
AnnouncementType.SESSION)
|
||||
}
|
||||
}
|
||||
.exception<ScriptUnavailableException> {
|
||||
|
@ -2118,7 +2123,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_retryJob = null;
|
||||
_liveTryJob?.cancel();
|
||||
_liveTryJob = null;
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to load video (ScriptException)", it, ::fetchVideo);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_video_scriptexception), it, ::fetchVideo);
|
||||
}
|
||||
}
|
||||
.exception<Throwable> {
|
||||
|
@ -2130,7 +2135,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_retryJob = null;
|
||||
_liveTryJob?.cancel();
|
||||
_liveTryJob = null;
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, "Failed to load video", it, ::fetchVideo);
|
||||
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_video), it, ::fetchVideo);
|
||||
}
|
||||
} else TaskHandler(IPlatformVideoDetails::class.java, {fragment.lifecycleScope});
|
||||
|
||||
|
@ -2171,7 +2176,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
val toWait = _liveStreamCheckInterval.toList().sortedBy { abs(diffSeconds - it.first) }.firstOrNull()?.second?.toLong() ?: return;
|
||||
|
||||
fragment.lifecycleScope.launch(Dispatchers.Main){
|
||||
UIDialogs.toast(context, "Not yet available, retrying in ${toWait}s");
|
||||
UIDialogs.toast(context, context.getString(R.string.not_yet_available_retrying_in_time_s).replace("{time}", toWait.toString()));
|
||||
}
|
||||
|
||||
_liveTryJob?.cancel();
|
||||
|
@ -2185,7 +2190,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
if(videoDetail.datetime != null && videoDetail.live == null && !videoDetail.video.videoSources.any()) {
|
||||
if(videoDetail.datetime!! > OffsetDateTime.now())
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(context, "Planned in ${videoDetail.datetime?.toHumanNowDiffString(true)}");
|
||||
UIDialogs.toast(context, context.getString(R.string.planned_in) + " ${videoDetail.datetime?.toHumanNowDiffString(true)}");
|
||||
}
|
||||
startLiveTry(liveTryVideo);
|
||||
}
|
||||
|
@ -2198,7 +2203,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to live try fetch video.", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.toast(context, "Failed to retry for live stream");
|
||||
UIDialogs.toast(context, context.getString(R.string.failed_to_retry_for_live_stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ abstract class VideoListEditorView : LinearLayout {
|
|||
}
|
||||
|
||||
protected fun setVideoCount(videoCount: Int = -1) {
|
||||
_textMetadata.text = if (videoCount == -1) "" else "${videoCount} videos";
|
||||
_textMetadata.text = if (videoCount == -1) "" else "${videoCount} " + context.getString(R.string.videos);
|
||||
}
|
||||
|
||||
protected fun setVideos(videos: List<IPlatformVideo>?, canEdit: Boolean) {
|
||||
|
@ -105,7 +105,7 @@ abstract class VideoListEditorView : LinearLayout {
|
|||
.into(it);
|
||||
};
|
||||
} else {
|
||||
_textMetadata.text = "0 videos";
|
||||
_textMetadata.text = "0 " + context.getString(R.string.videos);
|
||||
if(_imagePlaylistThumbnail != null) {
|
||||
Glide.with(_imagePlaylistThumbnail)
|
||||
.load(R.drawable.placeholder_video_thumbnail)
|
||||
|
|
|
@ -35,7 +35,7 @@ class GeneralTopBarFragment : TopFragment() {
|
|||
val view = inflater.inflate(R.layout.fragment_overview_top_bar, container, false);
|
||||
|
||||
view.findViewById<ImageView>(R.id.app_icon).setOnClickListener {
|
||||
UIDialogs.toast("This app is in development. Please submit bug reports and understand that many features are incomplete.", true);
|
||||
UIDialogs.toast(getString(R.string.this_app_is_in_development_please_submit_bug_reports_and_understand_that_many_features_are_incomplete), true);
|
||||
};
|
||||
|
||||
val buttonSearch: ImageButton = view.findViewById(R.id.button_search);
|
||||
|
|
|
@ -194,7 +194,7 @@ class SearchTopBarFragment : TopFragment() {
|
|||
if (editSearch != null) {
|
||||
val text = editSearch.text.toString();
|
||||
if (text.length < 3) {
|
||||
UIDialogs.toast("Please use at least 3 characters");
|
||||
UIDialogs.toast(getString(R.string.please_use_at_least_3_characters));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,8 @@
|
|||
<string name="incompatible">The operation failed because it is fundamentally incompatible with this device</string>
|
||||
<string name="invalid">The operation failed because one or more of the APKs was invalid</string>
|
||||
<string name="not_enough_storage">The operation failed because of storage issues</string>
|
||||
<string name="live">LIVE</string>
|
||||
<string name="live_capitalized">LIVE</string>
|
||||
<string name="live">Live</string>
|
||||
<string name="click_to_read_more">Click to read more</string>
|
||||
<string name="click_to_hide">Click to hide</string>
|
||||
<string name="version">Version</string>
|
||||
|
@ -184,6 +185,7 @@
|
|||
<string name="create">Create</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="confirm_delete_playlist">Are you sure you want to delete this playlist?</string>
|
||||
<string name="confirm_delete_subscription">Are you sure you want to delete this subscription?</string>
|
||||
|
@ -512,6 +514,176 @@
|
|||
<string name="enable_where_this_plugins_content_are_visible">Enable where this plugin\'s content are visible</string>
|
||||
<string name="show_content_in_home_tab">Show content in home tab</string>
|
||||
<string name="show_content_in_search_results">Show content in search results</string>
|
||||
<string name="no_valid_url_provided">No valid URL provided..</string>
|
||||
<string name="invalid_config_format">Invalid Config Format</string>
|
||||
<string name="failed_to_fetch_configuration">Failed to fetch configuration</string>
|
||||
<string name="failed_to_fetch_script">Failed to fetch script</string>
|
||||
<string name="url_access">URL Access</string>
|
||||
<string name="the_plugin_will_have_access_to_the_following_domains">The plugin will have access to the following domains</string>
|
||||
<string name="eval_access">Eval Access</string>
|
||||
<string name="the_plugin_will_have_access_to_eval_capability_remote_injection">The plugin will have access to eval capability (remote injection)</string>
|
||||
<string name="failed_to_scan_qr_code">Failed to scan QR code</string>
|
||||
<string name="not_a_plugin_url">Not a plugin URL</string>
|
||||
<string name="scan_a_qr_code">Scan a QR Code</string>
|
||||
<string name="not_implemented_yet">Not implemented yet..</string>
|
||||
<string name="unknown_context">Unknown Context</string>
|
||||
<string name="something_went_wrong_missing_stack_trace">Something went wrong... missing stack trace?</string>
|
||||
<string name="logs_already_submitted">Logs already submitted.</string>
|
||||
<string name="no_logs_found">No logs found.</string>
|
||||
<string name="failed_automated_share_share_manually">Failed automated share, share manually?</string>
|
||||
<string name="shared_id">Shared {id}</string>
|
||||
<string name="unhandled_exception_in_vs">Unhandled exception in VS</string>
|
||||
<string name="send_exception_to_developers">Send exception to developers...</string>
|
||||
<string name="your_license_key_has_been_set_an_app_restart_might_be_required">Your license key has been set!\nAn app restart might be required.</string>
|
||||
<string name="invalid_license_format">Invalid license format</string>
|
||||
<string name="unknown_content_format">Unknown content format</string>
|
||||
<string name="unknown_file_format">Unknown file format</string>
|
||||
<string name="unknown_polycentric_format">Unknown Polycentric format</string>
|
||||
<string name="unknown_url_format">Unknown url format</string>
|
||||
<string name="failed_to_handle_file">Failed to handle file</string>
|
||||
<string name="unknown_reconstruction_type">Unknown reconstruction type</string>
|
||||
<string name="failed_to_parse_newpipe_subscriptions">Failed to parse NewPipe Subscriptions</string>
|
||||
<string name="failed_to_generate_qr_code">Failed to generate QR code</string>
|
||||
<string name="share_text">Share Text</string>
|
||||
<string name="copied_text">Copied Text</string>
|
||||
<string name="must_be_at_least_3_characters_long">Must be at least 3 characters long.</string>
|
||||
<string name="failed_to_create_profile">Failed to create profile.</string>
|
||||
<string name="failed_to_fully_backfill_servers">Failed to fully backfill servers.</string>
|
||||
<string name="sign_in_to_this_identity">Sign in to this identity</string>
|
||||
<string name="text_field_does_not_contain_any_data">Text field does not contain any data</string>
|
||||
<string name="not_a_valid_url">Not a valid URL</string>
|
||||
<string name="this_profile_is_already_imported">This profile is already imported</string>
|
||||
<string name="failed_to_import_profile">Failed to import profile:</string>
|
||||
<string name="failed_to_backfill_client">Failed to backfill client</string>
|
||||
<string name="are_you_sure_you_want_to_remove_this_profile">Are you sure you want to remove this profile?</string>
|
||||
<string name="no_process_handle_set">No process handle set</string>
|
||||
<string name="name_must_be_at_least_3_characters_long">Name must be at least 3 characters long</string>
|
||||
<string name="process_handle_unset">Process handle unset</string>
|
||||
<string name="failed_to_read_image">Failed to read image</string>
|
||||
<string name="changes_have_been_saved">Changes have been saved</string>
|
||||
<string name="failed_to_synchronize_changes">Failed to synchronize changes</string>
|
||||
<string name="image_picker_cancelled">Image picker cancelled</string>
|
||||
<string name="you_are_now_in_developer_mode">You are now in developer mode</string>
|
||||
<string name="subscribers">Subscribers</string>
|
||||
<string name="find_name_on">Find {name} on</string>
|
||||
<string name="failed_to_fetch">Failed to fetch</string>
|
||||
<string name="thanks_for_your_purchase_a_key_will_be_sent_to_your_email_after_your_payment_has_been_received">Thanks for your purchase, a key will be sent to your email after your payment has been received!</string>
|
||||
<string name="payment_failed">Payment failed</string>
|
||||
<string name="payment_succeeded">Payment succeeded</string>
|
||||
<string name="enter_license_key">Enter license key</string>
|
||||
<string name="invalid_license_key">Invalid license key</string>
|
||||
<string name="license">License</string>
|
||||
<string name="failed_to_activate_key">Failed to activate key</string>
|
||||
<string name="no_source_enabled_to_support_this_channel">No source enabled to support this channel</string>
|
||||
<string name="do_you_want_to_convert_channel_channelname_to_a_playlist">Do you want to convert channel {channelName} to a playlist?</string>
|
||||
<string name="failed_to_convert_channel">Failed to convert channel</string>
|
||||
<string name="page">Page</string>
|
||||
<string name="hide">Hide</string>
|
||||
<string name="hide_from_home">Hide from Home</string>
|
||||
<string name="play_feed_as_queue">Play Feed as Queue</string>
|
||||
<string name="play_entire_feed">Play entire feed</string>
|
||||
<string name="queued">Queued</string>
|
||||
<string name="used">Used</string>
|
||||
<string name="available">Available</string>
|
||||
<string name="failed_to_load_next_page">Failed to load next page</string>
|
||||
<string name="plugin_pluginname_failed_message">Plugin {pluginName} failed:\n{message}</string>
|
||||
<string name="plugin_failed_due_to">Plugin failed due to:</string>
|
||||
<string name="failed_to_get_home_plugin">Failed to get Home\nPlugin</string>
|
||||
<string name="failed_to_get_home">Failed to get Home</string>
|
||||
<string name="no_home_available">No home available</string>
|
||||
<string name="no_home_page_is_available_please_check_if_you_are_connected_to_the_internet_and_refresh">No home page is available, please check if you are connected to the internet and refresh.</string>
|
||||
<string name="import_playlists">Import Playlists</string>
|
||||
<string name="playlists_imported">playlists imported.</string>
|
||||
<string name="index_out_of_size_selected">{index} out of {size} selected</string>
|
||||
<string name="import_subscriptions">Import Subscriptions</string>
|
||||
<string name="subscriptions_imported">subscriptions imported.</string>
|
||||
<string name="edit_playlist">Edit playlist</string>
|
||||
<string name="share_as_text">Share as Text</string>
|
||||
<string name="share_as_a_list_of_video_urls">Share as a list of video urls</string>
|
||||
<string name="share_as_import">Share as Import</string>
|
||||
<string name="share_as_a_import_file_for_grayjay">Share as a import file for Grayjay</string>
|
||||
<string name="failed_to_load_playlist">Failed to load playlist</string>
|
||||
<string name="please_wait_for_playlist_to_finish_loading">Please wait for playlist to finish loading</string>
|
||||
<string name="playlist_copied_as_local_playlist">Playlist copied as local playlist</string>
|
||||
<string name="are_you_sure_you_want_to_delete_the_downloaded_videos">Are you sure you want to delete the downloaded videos?</string>
|
||||
<string name="create_new_playlist">Create new playlist</string>
|
||||
<string name="expected_media_content_found">Expected media content, found</string>
|
||||
<string name="failed_to_load_post">Failed to load post.</string>
|
||||
<string name="replies">replies</string>
|
||||
<string name="plugin_settings_saved">Plugin settings saved</string>
|
||||
<string name="plugin_settings">Plugin settings</string>
|
||||
<string name="these_settings_are_defined_by_the_plugin">These settings are defined by the plugin</string>
|
||||
<string name="failed_to_load_source">Failed to load source</string>
|
||||
<string name="check_for_updates">Check for updates</string>
|
||||
<string name="checks_for_new_versions_of_the_source">Checks for new versions of the source</string>
|
||||
<string name="authentication">Authentication</string>
|
||||
<string name="sign_out_of_the_platform">Sign out of the platform</string>
|
||||
<string name="import_your_subscriptions_from_this_source">Import your subscriptions from this source</string>
|
||||
<string name="import_your_playlists_from_this_source">Import your playlists from this source</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="sign_into_the_platform_of_this_source">Sign into the platform of this source</string>
|
||||
<string name="management">Management</string>
|
||||
<string name="uninstall">Uninstall</string>
|
||||
<string name="removes_the_plugin_from_the_app">Removes the plugin from the app</string>
|
||||
<string name="delete_captcha">Delete Captcha</string>
|
||||
<string name="deletes_stored_captcha_answer_for_this_plugin">Deletes stored captcha answer for this plugin</string>
|
||||
<string name="failed_to_retrieve_playlists">Failed to retrieve playlists.</string>
|
||||
<string name="subscriptioncount_user_subscriptions_retrieved">{subscriptionCount} user subscriptions retrieved.</string>
|
||||
<string name="failed_to_retrieve_subscriptions">Failed to retrieve subscriptions.</string>
|
||||
<string name="are_you_sure_you_want_to_uninstall">Are you sure you want to uninstall</string>
|
||||
<string name="uninstalled">Uninstalled </string>
|
||||
<string name="failed_to_check_for_updates">Failed to check for updates</string>
|
||||
<string name="plugin_is_fully_up_to_date">Plugin is fully up to date</string>
|
||||
<string name="rate_limit_warning">Rate Limit Warning</string>
|
||||
<string name="this_is_a_temporary_measure_to_prevent_people_from_hitting_rate_limit_until_we_have_better_support_for_lots_of_subscriptions">This is a temporary measure to prevent people from hitting rate limit until we have better support for lots of subscriptions.</string>
|
||||
<string name="you_have_too_many_subscriptions_for_the_following_plugins">\n\nYou have too many subscriptions for the following plugins:\n</string>
|
||||
<string name="posts">Posts</string>
|
||||
<string name="planned">Planned</string>
|
||||
<string name="no_results_found_swipe_down_to_refresh">No results found\nSwipe down to refresh</string>
|
||||
<string name="overlay">Overlay</string>
|
||||
<string name="reload">Reload</string>
|
||||
<string name="watching_now">watching now</string>
|
||||
<string name="views">views</string>
|
||||
<string name="planned_in">Planned in</string>
|
||||
<string name="failed_to_get_playback_tracker">Failed to get Playback Tracker</string>
|
||||
<string name="exception_retrieving_live_events">Exception retrieving live events:</string>
|
||||
<string name="exception_retrieving_live_chat_window">Exception retrieving live chat window:</string>
|
||||
<string name="live_chat_failed_to_load">Live chat failed to load</string>
|
||||
<string name="unsupported_cast_format">Unsupported Cast format</string>
|
||||
<string name="failed_to_load_media">Failed to load media</string>
|
||||
<string name="offline_playback">Offline Playback</string>
|
||||
<string name="media_error">Media Error</string>
|
||||
<string name="the_media_source_encountered_an_unauthorized_error_this_might_be_solved_by_a_plugin_reload_would_you_like_to_reload_experimental">The media source encountered an unauthorized error.\nThis might be solved by a plugin reload.\nWould you like to reload?\n(Experimental)</string>
|
||||
<string name="playback_rate">Playback Rate</string>
|
||||
<string name="quality">Quality</string>
|
||||
<string name="offline_video">Offline Video</string>
|
||||
<string name="offline_audio">Offline Audio</string>
|
||||
<string name="offline_subtitles">Offline Subtitles</string>
|
||||
<string name="stream_video">Stream Video</string>
|
||||
<string name="stream_audio">Stream Audio</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="subtitles">Subtitles</string>
|
||||
<string name="unavailable_video">Unavailable video</string>
|
||||
<string name="this_video_is_unavailable">This video is unavailable.</string>
|
||||
<string name="there_was_an_unavailable_video_in_your_queue_videoname_by_authorname">There was an unavailable video in your queue [{videoName}] by [{authorName}].</string>
|
||||
<string name="back">Back</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="play">Play</string>
|
||||
<string name="pauses_the_video">Pauses the video</string>
|
||||
<string name="resumes_the_video">Resumes the video</string>
|
||||
<string name="video_without_source">Video without source</string>
|
||||
<string name="there_was_a_in_your_queue_videoname_by_authorname_without_the_required_source_being_enabled_playback_was_skipped">There was a in your queue [{videoName}] by [{authorName}] without the required source being enabled, playback was skipped.</string>
|
||||
<string name="failed_to_load_video_scriptimplementationexception">Failed to load video (ScriptImplementationException)</string>
|
||||
<string name="invalid_video">Invalid video</string>
|
||||
<string name="there_was_an_invalid_video_in_your_queue_videoname_by_authorname_playback_was_skipped">There was an invalid video in your queue [{videoName}] by [{authorName}], playback was skipped.</string>
|
||||
<string name="age_restricted_video">Age restricted video</string>
|
||||
<string name="there_was_an_age_restricted_video_in_your_queue_videoname_by_authorname_this_video_was_not_accessible_and_playback_was_skipped">There was an age restricted video in your queue [{videoName}] by [{authorName}], this video was not accessible and playback was skipped.</string>
|
||||
<string name="failed_to_load_video_scriptexception">Failed to load video (ScriptException)</string>
|
||||
<string name="failed_to_load_video">Failed to load video</string>
|
||||
<string name="not_yet_available_retrying_in_time_s">Not yet available, retrying in {time}s</string>
|
||||
<string name="failed_to_retry_for_live_stream">Failed to retry for live stream</string>
|
||||
<string name="this_app_is_in_development_please_submit_bug_reports_and_understand_that_many_features_are_incomplete">This app is in development. Please submit bug reports and understand that many features are incomplete.</string>
|
||||
<string name="please_use_at_least_3_characters">Please use at least 3 characters</string>
|
||||
<string-array name="casting_device_type_array">
|
||||
<item>FastCast</item>
|
||||
<item>ChromeCast</item>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3090ca3af03ce276fc167d47f49daa76a5b67dd7
|
||||
Subproject commit dfecd64655d1434d5d9345acadade6388942dc7b
|
4
lint.xml
Normal file
4
lint.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<issue id="SpUsage" severity="ignore" />
|
||||
</lint>
|
Loading…
Add table
Reference in a new issue