commit
cebd3d4f5f
102 changed files with 2397 additions and 1077 deletions
|
|
@ -18,8 +18,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
|
||||
versionCode 41
|
||||
versionName "1.17.8"
|
||||
versionCode 48
|
||||
versionName "1.19.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
|
@ -53,10 +53,12 @@ android {
|
|||
play {
|
||||
buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'true'
|
||||
buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'true'
|
||||
buildConfigField 'boolean', 'PAYMENT_LINKS_AVAILABLE', 'false' // Google Play Payments Policy, see #1463
|
||||
}
|
||||
fdroid {
|
||||
buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'false'
|
||||
buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'false'
|
||||
buildConfigField 'boolean', 'PAYMENT_LINKS_AVAILABLE', 'true'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +114,7 @@ dependencies {
|
|||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
|
||||
// Material design
|
||||
implementation "com.google.android.material:material:1.9.0"
|
||||
implementation "com.google.android.material:material:1.13.0"
|
||||
|
||||
// LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
|
||||
|
|
|
|||
|
|
@ -87,6 +87,15 @@
|
|||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
<!-- UnifiedPush link activity to facilitate distributor selection, see https://unifiedpush.org/developers/spec/android/#link-activity -->
|
||||
<activity android:name=".up.LinkActivity" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="unifiedpush" android:host="link" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Subscriber foreground service for hosts other than ntfy.sh -->
|
||||
<service
|
||||
android:name=".service.SubscriberService"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package io.heckel.ntfy.app
|
||||
|
||||
import android.app.Application
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
|
|
@ -12,4 +13,11 @@ class Application : Application() {
|
|||
}
|
||||
repository
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (repository.getDynamicColorsEnabled()) {
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ class Backuper(val context: Context) {
|
|||
if (settings.darkMode != null) {
|
||||
repository.setDarkMode(settings.darkMode)
|
||||
}
|
||||
if (settings.dynamicColors != null) {
|
||||
repository.setDynamicColorsEnabled(settings.dynamicColors)
|
||||
}
|
||||
if (settings.connectionProtocol != null) {
|
||||
repository.setConnectionProtocol(settings.connectionProtocol)
|
||||
}
|
||||
|
|
@ -234,6 +237,7 @@ class Backuper(val context: Context) {
|
|||
autoDownloadMaxSize = repository.getAutoDownloadMaxSize(),
|
||||
autoDeleteSeconds = repository.getAutoDeleteSeconds(),
|
||||
darkMode = repository.getDarkMode(),
|
||||
dynamicColors = repository.getDynamicColorsEnabled(),
|
||||
connectionProtocol = repository.getConnectionProtocol(),
|
||||
broadcastEnabled = repository.getBroadcastEnabled(),
|
||||
recordLogs = repository.getRecordLogs(),
|
||||
|
|
@ -357,6 +361,7 @@ data class Settings(
|
|||
val autoDownloadMaxSize: Long?,
|
||||
val autoDeleteSeconds: Long?,
|
||||
val darkMode: Int?,
|
||||
val dynamicColors: Boolean?,
|
||||
val connectionProtocol: String?,
|
||||
val broadcastEnabled: Boolean?,
|
||||
val recordLogs: Boolean?,
|
||||
|
|
|
|||
|
|
@ -274,6 +274,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
return sharedPrefs.getInt(SHARED_PREFS_DARK_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
|
||||
fun setDynamicColorsEnabled(enabled: Boolean) {
|
||||
sharedPrefs.edit()
|
||||
.putBoolean(SHARED_PREFS_DYNAMIC_COLORS, enabled)
|
||||
.commit()
|
||||
}
|
||||
|
||||
fun getDynamicColorsEnabled(): Boolean {
|
||||
return sharedPrefs.getBoolean(SHARED_PREFS_DYNAMIC_COLORS, false)
|
||||
}
|
||||
|
||||
fun setConnectionProtocol(connectionProtocol: String) {
|
||||
sharedPrefs.edit()
|
||||
.putString(SHARED_PREFS_CONNECTION_PROTOCOL, connectionProtocol)
|
||||
|
|
@ -527,6 +537,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
|
||||
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
|
||||
const val SHARED_PREFS_DARK_MODE = "DarkMode"
|
||||
const val SHARED_PREFS_DYNAMIC_COLORS = "DynamicColors"
|
||||
const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled"
|
||||
const val SHARED_PREFS_UNIFIEDPUSH_ENABLED = "UnifiedPushEnabled"
|
||||
const val SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED = "InsistentMaxPriority"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import android.text.SpannedString
|
|||
import android.text.style.CharacterStyle
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.db.Notification
|
||||
|
|
@ -29,6 +28,7 @@ class NotificationService(val context: Context) {
|
|||
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
private val repository = Repository.getInstance(context)
|
||||
private val markwon = MarkwonFactory.createForNotification(context)
|
||||
private val appBaseUrl = context.getString(R.string.app_base_url)
|
||||
|
||||
fun display(subscription: Subscription, notification: Notification) {
|
||||
Log.d(TAG, "Displaying notification $notification")
|
||||
|
|
@ -91,14 +91,14 @@ class NotificationService(val context: Context) {
|
|||
}
|
||||
|
||||
private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false) {
|
||||
val title = formatTitle(subscription, notification)
|
||||
val title = formatTitle(appBaseUrl, subscription, notification)
|
||||
val groupId = if (subscription.dedicatedChannels) subscriptionGroupId(subscription) else DEFAULT_GROUP
|
||||
val channelId = toChannelId(groupId, notification.priority)
|
||||
val insistent = notification.priority == PRIORITY_MAX &&
|
||||
(repository.getInsistentMaxPriorityEnabled() || subscription.insistent == Repository.INSISTENT_MAX_PRIORITY_ENABLED)
|
||||
val builder = NotificationCompat.Builder(context, channelId)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(ContextCompat.getColor(context, Colors.notificationIcon(context)))
|
||||
.setColor(Colors.notificationIcon(context))
|
||||
.setContentTitle(title)
|
||||
.setOnlyAlertOnce(true) // Do not vibrate or play sound if already showing (updates!)
|
||||
.setAutoCancel(true) // Cancel when notification is clicked
|
||||
|
|
@ -365,7 +365,7 @@ class NotificationService(val context: Context) {
|
|||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(appBaseUrl, subscription))
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
|
||||
putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import android.os.IBinder
|
|||
import android.os.PowerManager
|
||||
import android.os.SystemClock
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.app.Application
|
||||
|
|
@ -296,7 +295,7 @@ class SubscriberService : Service() {
|
|||
}
|
||||
return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_notification_instant)
|
||||
.setColor(ContextCompat.getColor(this, Colors.notificationIcon(this)))
|
||||
.setColor(Colors.notificationIcon(this))
|
||||
.setContentTitle(title)
|
||||
.setContentText(text)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
package io.heckel.ntfy.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
|
|
@ -30,10 +32,10 @@ class AddFragment : DialogFragment() {
|
|||
private lateinit var appBaseUrl: String
|
||||
private var defaultBaseUrl: String? = null
|
||||
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var actionMenuItem: MenuItem
|
||||
private lateinit var subscribeView: View
|
||||
private lateinit var loginView: View
|
||||
private lateinit var positiveButton: Button
|
||||
private lateinit var negativeButton: Button
|
||||
|
||||
// Subscribe page
|
||||
private lateinit var subscribeTopicText: TextInputEditText
|
||||
|
|
@ -78,6 +80,21 @@ class AddFragment : DialogFragment() {
|
|||
// Build root view
|
||||
val view = requireActivity().layoutInflater.inflate(R.layout.fragment_add_dialog, null)
|
||||
|
||||
// Setup toolbar
|
||||
toolbar = view.findViewById(R.id.add_dialog_toolbar)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
toolbar.setOnMenuItemClickListener { menuItem ->
|
||||
if (menuItem.itemId == R.id.add_dialog_action_button) {
|
||||
onActionButtonClick()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
actionMenuItem = toolbar.menu.findItem(R.id.add_dialog_action_button)
|
||||
|
||||
// Main "pages"
|
||||
subscribeView = view.findViewById(R.id.add_dialog_subscribe_view)
|
||||
subscribeView.visibility = View.VISIBLE
|
||||
|
|
@ -136,6 +153,19 @@ class AddFragment : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
// Subscribe view validation
|
||||
val subscribeTextWatcher = AfterChangedTextWatcher {
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
subscribeTopicText.addTextChangedListener(subscribeTextWatcher)
|
||||
subscribeBaseUrlText.addTextChangedListener(subscribeTextWatcher)
|
||||
subscribeInstantDeliveryCheckbox.setOnCheckedChangeListener { _, _ ->
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
subscribeUseAnotherServerCheckbox.setOnCheckedChangeListener { _, _ ->
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
|
||||
// Username/password validation on type
|
||||
val loginTextWatcher = AfterChangedTextWatcher {
|
||||
validateInputLoginView()
|
||||
|
|
@ -144,51 +174,36 @@ class AddFragment : DialogFragment() {
|
|||
loginPasswordText.addTextChangedListener(loginTextWatcher)
|
||||
|
||||
// Build dialog
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.add_dialog_button_subscribe) { _, _ ->
|
||||
// This will be overridden below to avoid closing the dialog immediately
|
||||
}
|
||||
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
|
||||
// This will be overridden below
|
||||
}
|
||||
.create()
|
||||
val dialog = Dialog(requireContext(), R.style.Theme_App_FullScreenDialog)
|
||||
dialog.setContentView(view)
|
||||
|
||||
// Show keyboard when the dialog is shown (see https://stackoverflow.com/a/19573049/1440785)
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
||||
|
||||
// Add logic to disable "Subscribe" button on invalid input
|
||||
dialog.setOnShowListener {
|
||||
positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
positiveButton.isEnabled = false
|
||||
positiveButton.setOnClickListener {
|
||||
positiveButtonClick()
|
||||
}
|
||||
negativeButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||
negativeButton.setOnClickListener {
|
||||
negativeButtonClick()
|
||||
}
|
||||
val subscribeTextWatcher = AfterChangedTextWatcher {
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
subscribeTopicText.addTextChangedListener(subscribeTextWatcher)
|
||||
subscribeBaseUrlText.addTextChangedListener(subscribeTextWatcher)
|
||||
subscribeInstantDeliveryCheckbox.setOnCheckedChangeListener { _, _ ->
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
subscribeUseAnotherServerCheckbox.setOnCheckedChangeListener { _, _ ->
|
||||
validateInputSubscribeView()
|
||||
}
|
||||
validateInputSubscribeView()
|
||||
|
||||
// Focus topic text (keyboard is shown too, see above)
|
||||
subscribeTopicText.requestFocus()
|
||||
}
|
||||
// Initial validation
|
||||
validateInputSubscribeView()
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun positiveButtonClick() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.apply {
|
||||
setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Show keyboard after the dialog is fully visible
|
||||
subscribeTopicText.postDelayed({
|
||||
subscribeTopicText.requestFocus()
|
||||
val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.showSoftInput(subscribeTopicText, InputMethodManager.SHOW_FORCED)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
private fun onActionButtonClick() {
|
||||
val topic = subscribeTopicText.text.toString()
|
||||
val baseUrl = getBaseUrl()
|
||||
if (subscribeView.visibility == View.VISIBLE) {
|
||||
|
|
@ -280,16 +295,8 @@ class AddFragment : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun negativeButtonClick() {
|
||||
if (subscribeView.visibility == View.VISIBLE) {
|
||||
dialog?.cancel()
|
||||
} else if (loginView.visibility == View.VISIBLE) {
|
||||
showSubscribeView()
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateInputSubscribeView() {
|
||||
if (!this::positiveButton.isInitialized) return // As per crash seen in Google Play
|
||||
if (!this::actionMenuItem.isInitialized) return // As per crash seen in Google Play
|
||||
|
||||
// Show/hide things: This logic is intentionally kept simple. Do not simplify "just because it's pretty".
|
||||
val instantToggleAllowed = if (!BuildConfig.FIREBASE_AVAILABLE) {
|
||||
|
|
@ -327,11 +334,11 @@ class AddFragment : DialogFragment() {
|
|||
activity?.let {
|
||||
it.runOnUiThread {
|
||||
if (subscription != null || DISALLOWED_TOPICS.contains(topic)) {
|
||||
positiveButton.isEnabled = false
|
||||
actionMenuItem.isEnabled = false
|
||||
} else if (subscribeUseAnotherServerCheckbox.isChecked) {
|
||||
positiveButton.isEnabled = validTopic(topic) && validUrl(baseUrl)
|
||||
actionMenuItem.isEnabled = validTopic(topic) && validUrl(baseUrl)
|
||||
} else {
|
||||
positiveButton.isEnabled = validTopic(topic)
|
||||
actionMenuItem.isEnabled = validTopic(topic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -339,13 +346,13 @@ class AddFragment : DialogFragment() {
|
|||
}
|
||||
|
||||
private fun validateInputLoginView() {
|
||||
if (!this::positiveButton.isInitialized || !this::loginUsernameText.isInitialized || !this::loginPasswordText.isInitialized) {
|
||||
if (!this::actionMenuItem.isInitialized || !this::loginUsernameText.isInitialized || !this::loginPasswordText.isInitialized) {
|
||||
return // As per crash seen in Google Play
|
||||
}
|
||||
if (loginUsernameText.visibility == View.GONE) {
|
||||
positiveButton.isEnabled = true
|
||||
actionMenuItem.isEnabled = true
|
||||
} else {
|
||||
positiveButton.isEnabled = (loginUsernameText.text?.isNotEmpty() ?: false)
|
||||
actionMenuItem.isEnabled = (loginUsernameText.text?.isNotEmpty() ?: false)
|
||||
&& (loginPasswordText.text?.isNotEmpty() ?: false)
|
||||
}
|
||||
}
|
||||
|
|
@ -372,8 +379,11 @@ class AddFragment : DialogFragment() {
|
|||
|
||||
private fun showSubscribeView() {
|
||||
resetSubscribeView()
|
||||
positiveButton.text = getString(R.string.add_dialog_button_subscribe)
|
||||
negativeButton.text = getString(R.string.add_dialog_button_cancel)
|
||||
toolbar.setTitle(R.string.add_dialog_title)
|
||||
actionMenuItem.setTitle(R.string.add_dialog_button_subscribe)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
loginView.visibility = View.GONE
|
||||
subscribeView.visibility = View.VISIBLE
|
||||
if (subscribeTopicText.requestFocus()) {
|
||||
|
|
@ -385,8 +395,11 @@ class AddFragment : DialogFragment() {
|
|||
private fun showLoginView(activity: Activity) {
|
||||
resetLoginView()
|
||||
loginProgress.visibility = View.INVISIBLE
|
||||
positiveButton.text = getString(R.string.add_dialog_button_login)
|
||||
negativeButton.text = getString(R.string.add_dialog_button_back)
|
||||
toolbar.setTitle(R.string.add_dialog_login_title)
|
||||
actionMenuItem.setTitle(R.string.add_dialog_button_login)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
showSubscribeView()
|
||||
}
|
||||
subscribeView.visibility = View.GONE
|
||||
loginView.visibility = View.VISIBLE
|
||||
if (loginUsernameText.requestFocus()) {
|
||||
|
|
@ -400,7 +413,7 @@ class AddFragment : DialogFragment() {
|
|||
subscribeBaseUrlText.isEnabled = enable
|
||||
subscribeInstantDeliveryCheckbox.isEnabled = enable
|
||||
subscribeUseAnotherServerCheckbox.isEnabled = enable
|
||||
positiveButton.isEnabled = enable
|
||||
actionMenuItem.isEnabled = enable
|
||||
}
|
||||
|
||||
private fun resetSubscribeView() {
|
||||
|
|
@ -413,7 +426,7 @@ class AddFragment : DialogFragment() {
|
|||
private fun enableLoginView(enable: Boolean) {
|
||||
loginUsernameText.isEnabled = enable
|
||||
loginPasswordText.isEnabled = enable
|
||||
positiveButton.isEnabled = enable
|
||||
actionMenuItem.isEnabled = enable
|
||||
if (enable && loginUsernameText.requestFocus()) {
|
||||
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.showSoftInput(loginUsernameText, InputMethodManager.SHOW_IMPLICIT)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package io.heckel.ntfy.ui
|
||||
|
||||
import android.widget.TextView
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import io.heckel.ntfy.R
|
||||
|
||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
|
||||
/**
|
||||
* Show [ListPreference] and [EditTextPreference] dialog by [MaterialAlertDialogBuilder]
|
||||
*/
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||
when (preference) {
|
||||
is ListPreference -> {
|
||||
val prefIndex = preference.entryValues.indexOf(preference.value)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(preference.title)
|
||||
.setSingleChoiceItems(preference.entries, prefIndex) { dialog, index ->
|
||||
val newValue = preference.entryValues[index].toString()
|
||||
if (preference.callChangeListener(newValue)) {
|
||||
preference.value = newValue
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
is EditTextPreference -> {
|
||||
val view = layoutInflater.inflate(R.layout.preference_dialog_edittext_edited, null)
|
||||
var message = ""
|
||||
var hint = ""
|
||||
if (preference.extras.getString("message") != null) {
|
||||
message = preference.extras.getString("message")!!
|
||||
}
|
||||
if (preference.extras.getString("hint") != null) {
|
||||
hint = preference.extras.getString("hint")!!
|
||||
}
|
||||
val messageView = view.findViewById<TextView>(android.R.id.message)
|
||||
messageView.text = message
|
||||
val editText = view.findViewById<TextInputEditText>(android.R.id.edit)
|
||||
editText.setText(preference.text.toString())
|
||||
editText.hint = hint
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(preference.title)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val newValue = editText.text.toString()
|
||||
if (preference.callChangeListener(newValue)) {
|
||||
preference.text = newValue
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
else -> super.onDisplayPreferenceDialog(preference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +1,93 @@
|
|||
package io.heckel.ntfy.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.util.isDarkThemeOn
|
||||
|
||||
class Colors {
|
||||
companion object {
|
||||
val refreshProgressIndicator = R.color.teal
|
||||
fun primary(context: Context): Int {
|
||||
return MaterialColors.getColor(context, R.attr.colorPrimary, Color.GREEN)
|
||||
}
|
||||
|
||||
fun onPrimary(context: Context): Int {
|
||||
return MaterialColors.getColor(context, R.attr.colorOnPrimary, Color.GREEN)
|
||||
}
|
||||
|
||||
fun notificationIcon(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.teal_light else R.color.teal
|
||||
return MaterialColors.getColor(context, R.attr.colorPrimary, Color.GREEN)
|
||||
}
|
||||
|
||||
fun linkColor(context: Context): Int {
|
||||
return MaterialColors.getColor(context, R.attr.colorPrimary, Color.GREEN)
|
||||
}
|
||||
|
||||
fun itemSelectedBackground(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.black_800b else R.color.gray_400
|
||||
}
|
||||
|
||||
fun cardBackground(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.black_800b else R.color.white
|
||||
}
|
||||
|
||||
fun cardSelectedBackground(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.black_700b else R.color.gray_500
|
||||
return ContextCompat.getColor(context, R.color.md_theme_surfaceContainerHigh)
|
||||
}
|
||||
|
||||
fun cardBackgroundColor(context: Context): Int {
|
||||
return ContextCompat.getColor(context, cardBackground(context))
|
||||
return if (isDarkThemeOn(context)) {
|
||||
MaterialColors.getColor(context, R.attr.colorSurfaceContainer, Color.GRAY)
|
||||
} else {
|
||||
MaterialColors.getColor(context, R.attr.colorSurface, Color.WHITE)
|
||||
}
|
||||
}
|
||||
|
||||
fun cardSelectedBackgroundColor(context: Context): Int {
|
||||
return ContextCompat.getColor(context, cardSelectedBackground(context))
|
||||
return if (isDarkThemeOn(context)) {
|
||||
MaterialColors.getColor(context, R.attr.colorSurfaceContainerHigh, Color.GRAY)
|
||||
} else {
|
||||
MaterialColors.getColor(context, R.attr.colorSurfaceContainerHighest, Color.GRAY)
|
||||
}
|
||||
}
|
||||
|
||||
fun statusBarNormal(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.black_900 else R.color.teal
|
||||
fun statusBarNormal(context: Context, dynamicColors: Boolean, darkMode: Boolean): Int {
|
||||
val default = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
context.resources.getColor(R.color.action_bar, null)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.resources.getColor(R.color.action_bar)
|
||||
}
|
||||
return if (dynamicColors) {
|
||||
// Use colorSurface for both light and dark mode when dynamic colors are enabled
|
||||
MaterialColors.getColor(context, R.attr.colorSurface, default)
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
fun statusBarActionMode(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.black_900 else R.color.teal_dark
|
||||
fun shouldUseLightStatusBar(dynamicColors: Boolean, darkMode: Boolean): Boolean {
|
||||
// Use light status bar (dark icons) when dynamic colors are enabled in light mode
|
||||
return dynamicColors && !darkMode
|
||||
}
|
||||
|
||||
fun toolbarTextColor(context: Context, dynamicColors: Boolean, darkMode: Boolean): Int {
|
||||
return if (dynamicColors) {
|
||||
// Use colorOnSurface (dark on light, light on dark) when dynamic colors are enabled
|
||||
MaterialColors.getColor(context, R.attr.colorOnSurface, Color.BLACK)
|
||||
} else {
|
||||
if (darkMode) {
|
||||
// In dark mode, toolbar is gray (surfaceContainer), so use light text
|
||||
MaterialColors.getColor(context, R.attr.colorOnSurface, Color.WHITE)
|
||||
} else {
|
||||
// In light mode, toolbar is teal (primary), so use white text
|
||||
MaterialColors.getColor(context, R.attr.colorOnPrimary, Color.WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dangerText(context: Context): Int {
|
||||
return if (isDarkThemeOn(context)) R.color.red_light else R.color.red_dark
|
||||
return MaterialColors.getColor(context, R.attr.colorError, Color.RED)
|
||||
}
|
||||
|
||||
fun swipeToRefreshColor(context: Context): Int {
|
||||
return MaterialColors.getColor(context, R.attr.colorPrimary, Color.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.ActionMode
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
|
@ -18,11 +17,15 @@ import android.widget.TextView
|
|||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.R
|
||||
|
|
@ -31,17 +34,30 @@ import io.heckel.ntfy.db.Notification
|
|||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.firebase.FirebaseMessenger
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.NotificationService
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import io.heckel.ntfy.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.copyToClipboard
|
||||
import io.heckel.ntfy.util.dangerButton
|
||||
import io.heckel.ntfy.util.decodeMessage
|
||||
import io.heckel.ntfy.util.displayName
|
||||
import io.heckel.ntfy.util.formatDateShort
|
||||
import io.heckel.ntfy.util.isDarkThemeOn
|
||||
import io.heckel.ntfy.util.randomSubscriptionId
|
||||
import io.heckel.ntfy.util.topicShortUrl
|
||||
import io.heckel.ntfy.util.topicUrl
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Date
|
||||
import kotlin.random.Random
|
||||
import androidx.core.view.size
|
||||
import androidx.core.view.get
|
||||
|
||||
|
||||
class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFragment.NotificationSettingsListener {
|
||||
class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSettingsListener {
|
||||
private val viewModel by viewModels<DetailViewModel> {
|
||||
DetailViewModelFactory((application as Application).repository)
|
||||
}
|
||||
|
|
@ -67,6 +83,36 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
|
||||
// Action mode stuff
|
||||
private var actionMode: ActionMode? = null
|
||||
private val actionModeCallback = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
actionMode = mode
|
||||
if (mode != null) {
|
||||
mode.menuInflater.inflate(R.menu.menu_detail_action_mode, menu)
|
||||
mode.title = "1" // One item selected
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.detail_action_mode_copy -> {
|
||||
onMultiCopyClick()
|
||||
true
|
||||
}
|
||||
R.id.detail_action_mode_delete -> {
|
||||
onMultiDeleteClick()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
endActionModeAndRedraw()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -78,9 +124,47 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
notifier = NotificationService(this)
|
||||
appBaseUrl = getString(R.string.app_base_url)
|
||||
|
||||
val toolbarLayout = findViewById<View>(R.id.app_bar_drawer)
|
||||
val dynamicColors = repository.getDynamicColorsEnabled()
|
||||
val darkMode = isDarkThemeOn(this)
|
||||
val statusBarColor = Colors.statusBarNormal(this, dynamicColors, darkMode)
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, dynamicColors, darkMode)
|
||||
toolbarLayout.setBackgroundColor(statusBarColor)
|
||||
|
||||
val toolbar = toolbarLayout.findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||
toolbar.setTitleTextColor(toolbarTextColor)
|
||||
toolbar.setNavigationIconTint(toolbarTextColor)
|
||||
toolbar.overflowIcon?.setTint(toolbarTextColor)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
// Set system status bar color and appearance
|
||||
window.statusBarColor = statusBarColor
|
||||
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars =
|
||||
Colors.shouldUseLightStatusBar(dynamicColors, darkMode)
|
||||
|
||||
// Set detail activity background: use theme background for dynamic colors, static gray for non-dynamic
|
||||
val detailContentLayout = findViewById<View>(R.id.detail_content_layout)
|
||||
if (repository.getDynamicColorsEnabled()) {
|
||||
detailContentLayout.setBackgroundColor(
|
||||
com.google.android.material.color.MaterialColors.getColor(
|
||||
this,
|
||||
android.R.attr.colorBackground,
|
||||
ContextCompat.getColor(this, R.color.detail_activity_background)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
detailContentLayout.setBackgroundColor(
|
||||
ContextCompat.getColor(this, R.color.detail_activity_background)
|
||||
)
|
||||
}
|
||||
|
||||
// Show 'Back' button
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
// Hide links that lead to payments, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
val howToLink = findViewById<TextView>(R.id.detail_how_to_link)
|
||||
howToLink.isVisible = BuildConfig.PAYMENT_LINKS_AVAILABLE
|
||||
|
||||
// Handle direct deep links to topic "ntfy://..."
|
||||
val url = intent?.data
|
||||
if (intent?.action == ACTION_VIEW && url != null) {
|
||||
|
|
@ -152,7 +236,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(appBaseUrl, subscription))
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
|
||||
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
|
||||
|
||||
|
|
@ -190,7 +274,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
// Swipe to refresh
|
||||
mainListContainer = findViewById(R.id.detail_notification_list_container)
|
||||
mainListContainer.setOnRefreshListener { refresh() }
|
||||
mainListContainer.setColorSchemeResources(Colors.refreshProgressIndicator)
|
||||
mainListContainer.setColorSchemeColors(Colors.swipeToRefreshColor(this))
|
||||
|
||||
// Update main list based on viewModel (& its datasource/livedata)
|
||||
val noEntriesText: View = findViewById(R.id.detail_no_notifications)
|
||||
|
|
@ -277,10 +361,11 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
val subscription = repository.getSubscription(subscriptionId) ?: return@launch
|
||||
subscriptionInstant = subscription.instant
|
||||
subscriptionMutedUntil = subscription.mutedUntil
|
||||
subscriptionDisplayName = displayName(subscription)
|
||||
subscriptionDisplayName = displayName(appBaseUrl, subscription)
|
||||
|
||||
showHideInstantMenuItems(subscriptionInstant)
|
||||
showHideMutedUntilMenuItems(subscriptionMutedUntil)
|
||||
showHideCopyMenuItems(subscription.baseUrl)
|
||||
updateTitle(subscriptionDisplayName)
|
||||
}
|
||||
}
|
||||
|
|
@ -312,10 +397,17 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_detail_action_bar, menu)
|
||||
this.menu = menu
|
||||
|
||||
// Tint menu icons based on theme
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, repository.getDynamicColorsEnabled(), isDarkThemeOn(this))
|
||||
for (i in 0 until menu.size) {
|
||||
menu[i].icon?.setTint(toolbarTextColor)
|
||||
}
|
||||
|
||||
// Show and hide buttons
|
||||
showHideInstantMenuItems(subscriptionInstant)
|
||||
showHideMutedUntilMenuItems(subscriptionMutedUntil)
|
||||
showHideCopyMenuItems(subscriptionBaseUrl)
|
||||
|
||||
// Regularly check if "notification muted" time has passed
|
||||
// NOTE: This is done here, because then we know that we've initialized the menu items.
|
||||
|
|
@ -559,6 +651,18 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun showHideCopyMenuItems(subscriptionBaseUrl: String) {
|
||||
if (!this::menu.isInitialized) {
|
||||
return
|
||||
}
|
||||
runOnUiThread {
|
||||
// Hide links that lead to payments, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
val copyUrlItem = menu.findItem(R.id.detail_menu_copy_url)
|
||||
copyUrlItem?.isVisible = appBaseUrl != subscriptionBaseUrl || BuildConfig.PAYMENT_LINKS_AVAILABLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTitle(subscriptionDisplayName: String) {
|
||||
runOnUiThread {
|
||||
title = subscriptionDisplayName
|
||||
|
|
@ -568,8 +672,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
private fun onClearClick() {
|
||||
Log.d(TAG, "Clearing all notifications for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
|
||||
|
||||
val builder = AlertDialog.Builder(this)
|
||||
val dialog = builder
|
||||
val dialog = MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.detail_clear_dialog_message)
|
||||
.setPositiveButton(R.string.detail_clear_dialog_permanently_delete) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
|
|
@ -600,8 +703,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
private fun onDeleteClick() {
|
||||
Log.d(TAG, "Deleting subscription ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
|
||||
|
||||
val builder = AlertDialog.Builder(this)
|
||||
val dialog = builder
|
||||
val dialog = MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.detail_delete_dialog_message)
|
||||
.setPositiveButton(R.string.detail_delete_dialog_permanently_delete) { _, _ ->
|
||||
Log.d(TAG, "Deleting subscription with subscription ID $subscriptionId (topic: $subscriptionTopic)")
|
||||
|
|
@ -664,33 +766,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
this.actionMode = mode
|
||||
if (mode != null) {
|
||||
mode.menuInflater.inflate(R.menu.menu_detail_action_mode, menu)
|
||||
mode.title = "1" // One item selected
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||
return when (item?.itemId) {
|
||||
R.id.detail_action_mode_copy -> {
|
||||
onMultiCopyClick()
|
||||
true
|
||||
}
|
||||
R.id.detail_action_mode_delete -> {
|
||||
onMultiDeleteClick()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun onMultiCopyClick() {
|
||||
Log.d(TAG, "Copying multiple notifications to clipboard")
|
||||
|
||||
|
|
@ -716,8 +791,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
private fun onMultiDeleteClick() {
|
||||
Log.d(TAG, "Showing multi-delete dialog for selected items")
|
||||
|
||||
val builder = AlertDialog.Builder(this)
|
||||
val dialog = builder
|
||||
val dialog = MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.detail_action_mode_delete_dialog_message)
|
||||
.setPositiveButton(R.string.detail_action_mode_delete_dialog_permanently_delete) { _, _ ->
|
||||
adapter.selected.map { notificationId -> viewModel.markAsDeleted(notificationId) }
|
||||
|
|
@ -735,18 +809,9 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
dialog.show()
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
endActionModeAndRedraw()
|
||||
}
|
||||
|
||||
private fun beginActionMode(notification: Notification) {
|
||||
actionMode = startActionMode(this)
|
||||
actionMode = startSupportActionMode(actionModeCallback)
|
||||
adapter.toggleSelection(notification.id)
|
||||
|
||||
// Fade status bar color
|
||||
val fromColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
|
||||
val toColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
|
||||
fadeStatusBarColor(window, fromColor, toColor)
|
||||
}
|
||||
|
||||
private fun finishActionMode() {
|
||||
|
|
@ -758,11 +823,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
|
|||
actionMode = null
|
||||
adapter.selected.clear()
|
||||
adapter.notifyItemRangeChanged(0, adapter.currentList.size)
|
||||
|
||||
// Fade status bar color
|
||||
val fromColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
|
||||
val toColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
|
||||
fadeStatusBarColor(window, fromColor, toColor)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.*
|
||||
import androidx.preference.Preference.OnPreferenceClickListener
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Repository
|
||||
|
|
@ -63,6 +65,24 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
.commit()
|
||||
}
|
||||
|
||||
val toolbarLayout = findViewById<AppBarLayout>(R.id.app_bar_drawer)
|
||||
val dynamicColors = repository.getDynamicColorsEnabled()
|
||||
val darkMode = isDarkThemeOn(this)
|
||||
val statusBarColor = Colors.statusBarNormal(this, dynamicColors, darkMode)
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, dynamicColors, darkMode)
|
||||
toolbarLayout.setBackgroundColor(statusBarColor)
|
||||
|
||||
val toolbar = toolbarLayout.findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||
toolbar.setTitleTextColor(toolbarTextColor)
|
||||
toolbar.setNavigationIconTint(toolbarTextColor)
|
||||
toolbar.overflowIcon?.setTint(toolbarTextColor)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
// Set system status bar color and appearance
|
||||
window.statusBarColor = statusBarColor
|
||||
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars =
|
||||
Colors.shouldUseLightStatusBar(dynamicColors, darkMode)
|
||||
|
||||
// Title
|
||||
val displayName = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
|
||||
title = displayName
|
||||
|
|
@ -87,6 +107,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
private lateinit var openChannelsPref: Preference
|
||||
private lateinit var iconSetLauncher: ActivityResultLauncher<String>
|
||||
private lateinit var iconRemovePref: Preference
|
||||
private lateinit var appBaseUrl: String
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.detail_preferences, rootKey)
|
||||
|
|
@ -96,6 +117,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
serviceManager = SubscriberServiceManager(requireActivity())
|
||||
notificationService = NotificationService(requireActivity())
|
||||
resolver = requireContext().applicationContext.contentResolver
|
||||
appBaseUrl = requireContext().getString(R.string.app_base_url)
|
||||
|
||||
// Create result launcher for custom icon (must be created in onCreatePreferences() directly)
|
||||
iconSetLauncher = createIconPickLauncher()
|
||||
|
|
@ -137,7 +159,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
private fun loadInstantPref() {
|
||||
val appBaseUrl = getString(R.string.app_base_url)
|
||||
val prefId = context?.getString(R.string.detail_settings_notifications_instant_key) ?: return
|
||||
val pref: SwitchPreference? = findPreference(prefId)
|
||||
val pref: SwitchPreferenceCompat? = findPreference(prefId)
|
||||
pref?.isVisible = BuildConfig.FIREBASE_AVAILABLE && subscription.baseUrl == appBaseUrl
|
||||
pref?.isChecked = subscription.instant
|
||||
pref?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
|
|
@ -148,7 +170,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
return subscription.instant
|
||||
}
|
||||
}
|
||||
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { preference ->
|
||||
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { preference ->
|
||||
if (preference.isChecked) {
|
||||
getString(R.string.detail_settings_notifications_instant_summary_on)
|
||||
} else {
|
||||
|
|
@ -159,7 +181,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
|
||||
private fun loadDedicatedChannelsPrefs() {
|
||||
val prefId = context?.getString(R.string.detail_settings_notifications_dedicated_channels_key) ?: return
|
||||
val pref: SwitchPreference? = findPreference(prefId)
|
||||
val pref: SwitchPreferenceCompat? = findPreference(prefId)
|
||||
pref?.isVisible = true
|
||||
pref?.isChecked = subscription.dedicatedChannels
|
||||
pref?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
|
|
@ -176,7 +198,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
return subscription.dedicatedChannels
|
||||
}
|
||||
}
|
||||
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { preference ->
|
||||
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { preference ->
|
||||
if (preference.isChecked) {
|
||||
getString(R.string.detail_settings_notifications_dedicated_channels_summary_on)
|
||||
} else {
|
||||
|
|
@ -381,7 +403,7 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
save(newSubscription)
|
||||
// Update activity title
|
||||
activity?.runOnUiThread {
|
||||
activity?.title = displayName(newSubscription)
|
||||
activity?.title = displayName(appBaseUrl, newSubscription)
|
||||
}
|
||||
// Update dedicated notification channel
|
||||
if (newSubscription.dedicatedChannels) {
|
||||
|
|
@ -394,9 +416,10 @@ class DetailSettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
pref?.summaryProvider = Preference.SummaryProvider<EditTextPreference> { provider ->
|
||||
if (TextUtils.isEmpty(provider.text)) {
|
||||
val appBaseUrl = context?.getString(R.string.app_base_url)
|
||||
getString(
|
||||
R.string.detail_settings_appearance_display_name_default_summary,
|
||||
displayName(subscription)
|
||||
displayName(appBaseUrl, subscription)
|
||||
)
|
||||
} else {
|
||||
provider.text
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import android.os.Bundle
|
|||
import android.provider.Settings
|
||||
import android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.ActionMode
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
|
@ -24,12 +23,25 @@ import android.widget.Toast
|
|||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.work.*
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.R
|
||||
|
|
@ -43,17 +55,28 @@ import io.heckel.ntfy.msg.DownloadType
|
|||
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||
import io.heckel.ntfy.service.SubscriberService
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import io.heckel.ntfy.util.*
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.dangerButton
|
||||
import io.heckel.ntfy.util.displayName
|
||||
import io.heckel.ntfy.util.formatDateShort
|
||||
import io.heckel.ntfy.util.isDarkThemeOn
|
||||
import io.heckel.ntfy.util.isIgnoringBatteryOptimizations
|
||||
import io.heckel.ntfy.util.maybeSplitTopicUrl
|
||||
import io.heckel.ntfy.util.randomSubscriptionId
|
||||
import io.heckel.ntfy.util.shortUrl
|
||||
import io.heckel.ntfy.util.topicShortUrl
|
||||
import io.heckel.ntfy.work.DeleteWorker
|
||||
import io.heckel.ntfy.work.PollWorker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.random.Random
|
||||
import androidx.core.view.size
|
||||
import androidx.core.view.get
|
||||
|
||||
class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.SubscribeListener, NotificationFragment.NotificationSettingsListener {
|
||||
class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, NotificationFragment.NotificationSettingsListener {
|
||||
private val viewModel by viewModels<SubscriptionsViewModel> {
|
||||
SubscriptionsViewModelFactory((application as Application).repository)
|
||||
}
|
||||
|
|
@ -69,11 +92,39 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
private lateinit var fab: FloatingActionButton
|
||||
|
||||
// Other stuff
|
||||
private var actionMode: ActionMode? = null
|
||||
private var workManager: WorkManager? = null // Context-dependent
|
||||
private var dispatcher: NotificationDispatcher? = null // Context-dependent
|
||||
private var appBaseUrl: String? = null // Context-dependent
|
||||
|
||||
// Action mode stuff
|
||||
private var actionMode: ActionMode? = null
|
||||
private val actionModeCallback = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
actionMode = mode
|
||||
if (mode != null) {
|
||||
mode.menuInflater.inflate(R.menu.menu_main_action_mode, menu)
|
||||
mode.title = "1" // One item selected
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.main_action_mode_delete -> {
|
||||
onMultiDeleteClick()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
endActionModeAndRedraw()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
|
@ -87,18 +138,44 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
appBaseUrl = getString(R.string.app_base_url)
|
||||
|
||||
// Action bar
|
||||
val toolbarLayout = findViewById<AppBarLayout>(R.id.app_bar_drawer)
|
||||
val dynamicColors = repository.getDynamicColorsEnabled()
|
||||
val darkMode = isDarkThemeOn(this)
|
||||
val statusBarColor = Colors.statusBarNormal(this, dynamicColors, darkMode)
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, dynamicColors, darkMode)
|
||||
toolbarLayout.setBackgroundColor(statusBarColor)
|
||||
|
||||
val toolbar = toolbarLayout.findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||
toolbar.setTitleTextColor(toolbarTextColor)
|
||||
toolbar.setNavigationIconTint(toolbarTextColor)
|
||||
toolbar.overflowIcon?.setTint(toolbarTextColor)
|
||||
setSupportActionBar(toolbar)
|
||||
title = getString(R.string.main_action_bar_title)
|
||||
|
||||
// Set system status bar color and appearance
|
||||
window.statusBarColor = statusBarColor
|
||||
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars =
|
||||
Colors.shouldUseLightStatusBar(dynamicColors, darkMode)
|
||||
|
||||
// Floating action button ("+")
|
||||
fab = findViewById(R.id.fab)
|
||||
fab.setOnClickListener {
|
||||
onSubscribeButtonClick()
|
||||
}
|
||||
|
||||
// Add bottom padding to FAB to account for navigation bar
|
||||
ViewCompat.setOnApplyWindowInsetsListener(fab) { view, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val layoutParams = view.layoutParams as androidx.constraintlayout.widget.ConstraintLayout.LayoutParams
|
||||
layoutParams.bottomMargin = systemBars.bottom
|
||||
view.layoutParams = layoutParams
|
||||
insets
|
||||
}
|
||||
|
||||
// Swipe to refresh
|
||||
mainListContainer = findViewById(R.id.main_subscriptions_list_container)
|
||||
mainListContainer.setOnRefreshListener { refreshAllSubscriptions() }
|
||||
mainListContainer.setColorSchemeResources(Colors.refreshProgressIndicator)
|
||||
mainListContainer.setColorSchemeColors(Colors.swipeToRefreshColor(this))
|
||||
|
||||
// Update main list based on viewModel (& its datasource/livedata)
|
||||
val noEntries: View = findViewById(R.id.main_no_subscriptions)
|
||||
|
|
@ -106,7 +183,15 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
val onSubscriptionLongClick = { s: Subscription -> onSubscriptionItemLongClick(s) }
|
||||
|
||||
mainList = findViewById(R.id.main_subscriptions_list)
|
||||
adapter = MainAdapter(repository, onSubscriptionClick, onSubscriptionLongClick)
|
||||
adapter = MainAdapter(
|
||||
repository,
|
||||
onSubscriptionClick,
|
||||
onSubscriptionLongClick,
|
||||
ResourcesCompat.getDrawable(resources, R.drawable.ic_circle, theme)!!.apply {
|
||||
setTint(Colors.primary(this@MainActivity))
|
||||
},
|
||||
Colors.onPrimary(this)
|
||||
)
|
||||
mainList.adapter = adapter
|
||||
|
||||
viewModel.list().observe(this) {
|
||||
|
|
@ -244,6 +329,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
}
|
||||
}
|
||||
|
||||
// Hide links that lead to payments, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
val howToLink = findViewById<TextView>(R.id.main_how_to_link)
|
||||
howToLink.isVisible = BuildConfig.PAYMENT_LINKS_AVAILABLE
|
||||
|
||||
// Create notification channels right away, so we can configure them immediately after installing the app
|
||||
dispatcher?.init()
|
||||
|
||||
|
|
@ -293,7 +382,19 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
val wsRemindTimeReached = repository.getWebSocketRemindTime() < System.currentTimeMillis()
|
||||
val showBanner = hasSelfHostedSubscriptions && wsRemindTimeReached && !usingWebSockets
|
||||
val wsBanner = findViewById<View>(R.id.main_banner_websocket)
|
||||
wsBanner.visibility = if (showBanner) View.VISIBLE else View.GONE
|
||||
if (showBanner) {
|
||||
wsBanner.visibility = View.VISIBLE
|
||||
if (!BuildConfig.PAYMENT_LINKS_AVAILABLE) {
|
||||
// Hide links that lead to payments, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
// This is a big fat hack, but I have to release this quickly ...
|
||||
val wsBannerMainText = findViewById<TextView>(R.id.main_banner_websocket_text)
|
||||
val raw = getString(R.string.main_banner_websocket_text)
|
||||
val unlinked = raw.replace(Regex("</?a[^>]*>"), "")
|
||||
wsBannerMainText.text = HtmlCompat.fromHtml(unlinked, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
}
|
||||
} else {
|
||||
wsBanner.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun showHideWebSocketReconnectBanner(subscriptions: List<Subscription>) {
|
||||
|
|
@ -372,6 +473,13 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_main_action_bar, menu)
|
||||
this.menu = menu
|
||||
|
||||
// Tint menu icons based on theme
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, repository.getDynamicColorsEnabled(), isDarkThemeOn(this))
|
||||
for (i in 0 until menu.size) {
|
||||
menu[i].icon?.setTint(toolbarTextColor)
|
||||
}
|
||||
|
||||
showHideNotificationMenuItems()
|
||||
checkSubscriptionsMuted() // This is done here, because then we know that we've initialized the menu
|
||||
return true
|
||||
|
|
@ -412,9 +520,13 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
}
|
||||
val mutedUntilSeconds = repository.getGlobalMutedUntil()
|
||||
runOnUiThread {
|
||||
// Show/hide in-app rate widget
|
||||
// Show/hide menu items based on build config
|
||||
val rateAppItem = menu.findItem(R.id.main_menu_rate)
|
||||
val docsItem = menu.findItem(R.id.main_menu_docs)
|
||||
val reportBugItem = menu.findItem(R.id.main_menu_report_bug)
|
||||
rateAppItem.isVisible = BuildConfig.RATE_APP_AVAILABLE
|
||||
docsItem.isVisible = BuildConfig.PAYMENT_LINKS_AVAILABLE // Google Payments Policy, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
reportBugItem.isVisible = BuildConfig.PAYMENT_LINKS_AVAILABLE // Google Payments Policy, see https://github.com/binwiederhier/ntfy/issues/1463
|
||||
|
||||
// Pause notification icons
|
||||
val notificationsEnabledItem = menu.findItem(R.id.main_menu_notifications_enabled)
|
||||
|
|
@ -460,10 +572,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
}
|
||||
true
|
||||
}
|
||||
R.id.main_menu_donate -> {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_donate_url))))
|
||||
true
|
||||
}
|
||||
R.id.main_menu_docs -> {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_docs_url))))
|
||||
true
|
||||
|
|
@ -591,7 +699,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
val topic = displayName(subscription)
|
||||
val topic = displayName(appBaseUrl, subscription)
|
||||
if (errorMessage == "") errorMessage = "$topic: ${e.message}"
|
||||
errors++
|
||||
}
|
||||
|
|
@ -618,7 +726,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
intent.putExtra(EXTRA_SUBSCRIPTION_ID, subscription.id)
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(appBaseUrl, subscription))
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
|
||||
intent.putExtra(EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
|
||||
startActivity(intent)
|
||||
|
|
@ -631,11 +739,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
|
||||
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
|
||||
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
|
||||
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
|
||||
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(appBaseUrl, subscription))
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
|
||||
private fun handleActionModeClick(subscription: Subscription) {
|
||||
adapter.toggleSelection(subscription.id)
|
||||
if (adapter.selected.size == 0) {
|
||||
|
|
@ -645,34 +752,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
this.actionMode = mode
|
||||
if (mode != null) {
|
||||
mode.menuInflater.inflate(R.menu.menu_main_action_mode, menu)
|
||||
mode.title = "1" // One item selected
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||
return when (item?.itemId) {
|
||||
R.id.main_action_mode_delete -> {
|
||||
onMultiDeleteClick()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun onMultiDeleteClick() {
|
||||
Log.d(DetailActivity.TAG, "Showing multi-delete dialog for selected items")
|
||||
|
||||
val builder = AlertDialog.Builder(this)
|
||||
val dialog = builder
|
||||
val dialog = MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.main_action_mode_delete_dialog_message)
|
||||
.setPositiveButton(R.string.main_action_mode_delete_dialog_permanently_delete) { _, _ ->
|
||||
adapter.selected.map { subscriptionId -> viewModel.remove(this, subscriptionId) }
|
||||
|
|
@ -690,15 +773,11 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
dialog.show()
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
endActionModeAndRedraw()
|
||||
}
|
||||
|
||||
private fun beginActionMode(subscription: Subscription) {
|
||||
actionMode = startActionMode(this)
|
||||
actionMode = startSupportActionMode(actionModeCallback)
|
||||
adapter.toggleSelection(subscription.id)
|
||||
|
||||
// Fade out FAB
|
||||
// Fade out FAB
|
||||
fab.alpha = 1f
|
||||
fab
|
||||
.animate()
|
||||
|
|
@ -709,11 +788,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
fab.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
// Fade status bar color
|
||||
val fromColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
|
||||
val toColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
|
||||
fadeStatusBarColor(window, fromColor, toColor)
|
||||
}
|
||||
|
||||
private fun finishActionMode() {
|
||||
|
|
@ -738,11 +812,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
fab.visibility = View.VISIBLE // Required to replace the old listener
|
||||
}
|
||||
})
|
||||
|
||||
// Fade status bar color
|
||||
val fromColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
|
||||
val toColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
|
||||
fadeStatusBarColor(window, fromColor, toColor)
|
||||
}
|
||||
|
||||
private fun redrawList() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package io.heckel.ntfy.ui
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -20,7 +21,13 @@ import io.heckel.ntfy.util.readBitmapFromUriOrNull
|
|||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
class MainAdapter(private val repository: Repository, private val onClick: (Subscription) -> Unit, private val onLongClick: (Subscription) -> Unit) :
|
||||
class MainAdapter(
|
||||
private val repository: Repository,
|
||||
private val onClick: (Subscription) -> Unit,
|
||||
private val onLongClick: (Subscription) -> Unit,
|
||||
private val countDrawable: Drawable,
|
||||
private val onPrimaryColor: Int
|
||||
) :
|
||||
ListAdapter<Subscription, MainAdapter.SubscriptionViewHolder>(TopicDiffCallback) {
|
||||
val selected = mutableSetOf<Long>() // Subscription IDs
|
||||
|
||||
|
|
@ -28,7 +35,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.fragment_main_item, parent, false)
|
||||
return SubscriptionViewHolder(view, repository, selected, onClick, onLongClick)
|
||||
return SubscriptionViewHolder(view, repository, selected, onClick, onLongClick, countDrawable, onPrimaryColor)
|
||||
}
|
||||
|
||||
/* Gets current topic and uses it to bind view. */
|
||||
|
|
@ -52,7 +59,15 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
|
|||
}
|
||||
|
||||
/* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */
|
||||
class SubscriptionViewHolder(itemView: View, private val repository: Repository, private val selected: Set<Long>, val onClick: (Subscription) -> Unit, val onLongClick: (Subscription) -> Unit) :
|
||||
class SubscriptionViewHolder(
|
||||
itemView: View,
|
||||
private val repository: Repository,
|
||||
private val selected: Set<Long>,
|
||||
val onClick: (Subscription) -> Unit,
|
||||
val onLongClick: (Subscription) -> Unit,
|
||||
private val countDrawable: Drawable,
|
||||
private val onPrimaryColor: Int
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private var subscription: Subscription? = null
|
||||
private val context: Context = itemView.context
|
||||
|
|
@ -64,6 +79,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
|
|||
private val notificationDisabledForeverImageView: View = itemView.findViewById(R.id.main_item_notification_disabled_forever_image)
|
||||
private val instantImageView: View = itemView.findViewById(R.id.main_item_instant_image)
|
||||
private val newItemsView: TextView = itemView.findViewById(R.id.main_item_new)
|
||||
private val appBaseUrl = context.getString(R.string.app_base_url)
|
||||
|
||||
fun bind(subscription: Subscription) {
|
||||
this.subscription = subscription
|
||||
|
|
@ -99,7 +115,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
|
|||
} else {
|
||||
imageView.setImageResource(R.drawable.ic_sms_gray_24dp)
|
||||
}
|
||||
nameView.text = displayName(subscription)
|
||||
nameView.text = displayName(appBaseUrl, subscription)
|
||||
statusView.text = statusMessage
|
||||
dateView.text = dateText
|
||||
dateView.visibility = if (isUnifiedPush) View.GONE else View.VISIBLE
|
||||
|
|
@ -111,11 +127,13 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
|
|||
} else {
|
||||
newItemsView.visibility = View.VISIBLE
|
||||
newItemsView.text = if (subscription.newCount <= 99) subscription.newCount.toString() else "99+"
|
||||
newItemsView.setTextColor(onPrimaryColor)
|
||||
newItemsView.background = countDrawable
|
||||
}
|
||||
itemView.setOnClickListener { onClick(subscription) }
|
||||
itemView.setOnLongClickListener { onLongClick(subscription); true }
|
||||
if (selected.contains(subscription.id)) {
|
||||
itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
|
||||
itemView.setBackgroundColor(Colors.itemSelectedBackground(context))
|
||||
} else {
|
||||
itemView.setBackgroundColor(Color.TRANSPARENT)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.os.Bundle
|
|||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -74,7 +75,7 @@ class NotificationFragment : DialogFragment() {
|
|||
muteForeverButton = view.findViewById(R.id.notification_dialog_forever)
|
||||
muteForeverButton.setOnClickListener{ onClick(Repository.MUTED_UNTIL_FOREVER) }
|
||||
|
||||
return AlertDialog.Builder(activity)
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(view)
|
||||
.create()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package io.heckel.ntfy.ui
|
|||
|
||||
import android.Manifest
|
||||
import android.app.AlarmManager
|
||||
import android.app.AlertDialog
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
|
|
@ -13,6 +12,7 @@ import android.os.Bundle
|
|||
import android.provider.Settings
|
||||
import android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
|
|
@ -21,10 +21,12 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.*
|
||||
import androidx.preference.Preference.OnPreferenceClickListener
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.gson.Gson
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.R
|
||||
|
|
@ -65,6 +67,28 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
repository = Repository.getInstance(this)
|
||||
serviceManager = SubscriberServiceManager(this)
|
||||
|
||||
val toolbarLayout = findViewById<View>(R.id.app_bar_drawer)
|
||||
val dynamicColors = repository.getDynamicColorsEnabled()
|
||||
val darkMode = isDarkThemeOn(this)
|
||||
val statusBarColor = Colors.statusBarNormal(
|
||||
this,
|
||||
dynamicColors,
|
||||
darkMode
|
||||
)
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, dynamicColors, darkMode)
|
||||
toolbarLayout.setBackgroundColor(statusBarColor)
|
||||
|
||||
val toolbar = toolbarLayout.findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||
toolbar.setTitleTextColor(toolbarTextColor)
|
||||
toolbar.setNavigationIconTint(toolbarTextColor)
|
||||
toolbar.overflowIcon?.setTint(toolbarTextColor)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
// Set system status bar color and appearance
|
||||
window.statusBarColor = statusBarColor
|
||||
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars =
|
||||
Colors.shouldUseLightStatusBar(dynamicColors, darkMode)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
settingsFragment = SettingsFragment() // Empty constructor!
|
||||
supportFragmentManager
|
||||
|
|
@ -128,7 +152,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
}
|
||||
}
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
class SettingsFragment : BasePreferenceFragment() {
|
||||
private lateinit var repository: Repository
|
||||
private lateinit var serviceManager: SubscriberServiceManager
|
||||
private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET
|
||||
|
|
@ -211,7 +235,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
|
||||
// Keep alerting for max priority
|
||||
val insistentMaxPriorityPrefId = context?.getString(R.string.settings_notifications_insistent_max_priority_key) ?: return
|
||||
val insistentMaxPriority: SwitchPreference? = findPreference(insistentMaxPriorityPrefId)
|
||||
val insistentMaxPriority: SwitchPreferenceCompat? = findPreference(insistentMaxPriorityPrefId)
|
||||
insistentMaxPriority?.isChecked = repository.getInsistentMaxPriorityEnabled()
|
||||
insistentMaxPriority?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
|
|
@ -221,7 +245,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
return repository.getInsistentMaxPriorityEnabled()
|
||||
}
|
||||
}
|
||||
insistentMaxPriority?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
|
||||
insistentMaxPriority?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { pref ->
|
||||
if (pref.isChecked) {
|
||||
getString(R.string.settings_notifications_insistent_max_priority_summary_enabled)
|
||||
} else {
|
||||
|
|
@ -324,11 +348,45 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
}
|
||||
}
|
||||
|
||||
// Dynamic colors
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val dynamicColorsEnabledPrefId = context?.getString(R.string.settings_general_dynamic_colors_key) ?: return
|
||||
val dynamicColorsEnabled: SwitchPreferenceCompat? = findPreference(dynamicColorsEnabledPrefId)
|
||||
dynamicColorsEnabled?.isChecked = repository.getDynamicColorsEnabled()
|
||||
dynamicColorsEnabled?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
repository.setDynamicColorsEnabled(value)
|
||||
|
||||
// Restart app
|
||||
val packageManager = requireContext().packageManager
|
||||
val packageName = requireContext().packageName
|
||||
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
||||
val componentName = intent!!.component
|
||||
val mainIntent = Intent.makeRestartActivityTask(componentName)
|
||||
startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
|
||||
return repository.getDynamicColorsEnabled()
|
||||
}
|
||||
}
|
||||
dynamicColorsEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { pref ->
|
||||
if (pref.isChecked) {
|
||||
getString(R.string.settings_general_dynamic_colors_summary_enabled)
|
||||
} else {
|
||||
getString(R.string.settings_general_dynamic_colors_summary_disabled)
|
||||
}
|
||||
}
|
||||
dynamicColorsEnabled?.isVisible = true
|
||||
}
|
||||
|
||||
// Default Base URL
|
||||
val appBaseUrl = getString(R.string.app_base_url)
|
||||
val defaultBaseUrlPrefId = context?.getString(R.string.settings_general_default_base_url_key) ?: return
|
||||
val defaultBaseUrl: EditTextPreference? = findPreference(defaultBaseUrlPrefId)
|
||||
defaultBaseUrl?.text = repository.getDefaultBaseUrl() ?: ""
|
||||
defaultBaseUrl?.extras?.putString("message", getString(R.string.settings_general_default_base_url_message))
|
||||
defaultBaseUrl?.extras?.putString("hint", getString(R.string.app_base_url))
|
||||
defaultBaseUrl?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putString(key: String, value: String?) {
|
||||
val baseUrl = value ?: return
|
||||
|
|
@ -355,7 +413,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
|
||||
// Broadcast enabled
|
||||
val broadcastEnabledPrefId = context?.getString(R.string.settings_advanced_broadcast_key) ?: return
|
||||
val broadcastEnabled: SwitchPreference? = findPreference(broadcastEnabledPrefId)
|
||||
val broadcastEnabled: SwitchPreferenceCompat? = findPreference(broadcastEnabledPrefId)
|
||||
broadcastEnabled?.isChecked = repository.getBroadcastEnabled()
|
||||
broadcastEnabled?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
|
|
@ -365,7 +423,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
return repository.getBroadcastEnabled()
|
||||
}
|
||||
}
|
||||
broadcastEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
|
||||
broadcastEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { pref ->
|
||||
if (pref.isChecked) {
|
||||
getString(R.string.settings_advanced_broadcast_summary_enabled)
|
||||
} else {
|
||||
|
|
@ -375,7 +433,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
|
||||
// Enable UnifiedPush
|
||||
val unifiedPushEnabledPrefId = context?.getString(R.string.settings_advanced_unifiedpush_key) ?: return
|
||||
val unifiedPushEnabled: SwitchPreference? = findPreference(unifiedPushEnabledPrefId)
|
||||
val unifiedPushEnabled: SwitchPreferenceCompat? = findPreference(unifiedPushEnabledPrefId)
|
||||
unifiedPushEnabled?.isChecked = repository.getUnifiedPushEnabled()
|
||||
unifiedPushEnabled?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
|
|
@ -385,7 +443,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
return repository.getUnifiedPushEnabled()
|
||||
}
|
||||
}
|
||||
unifiedPushEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
|
||||
unifiedPushEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { pref ->
|
||||
if (pref.isChecked) {
|
||||
getString(R.string.settings_advanced_unifiedpush_summary_enabled)
|
||||
} else {
|
||||
|
|
@ -420,7 +478,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
|
||||
// Record logs
|
||||
val recordLogsPrefId = context?.getString(R.string.settings_advanced_record_logs_key) ?: return
|
||||
val recordLogsEnabled: SwitchPreference? = findPreference(recordLogsPrefId)
|
||||
val recordLogsEnabled: SwitchPreferenceCompat? = findPreference(recordLogsPrefId)
|
||||
recordLogsEnabled?.isChecked = Log.getRecord()
|
||||
recordLogsEnabled?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
|
|
@ -433,7 +491,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
return Log.getRecord()
|
||||
}
|
||||
}
|
||||
recordLogsEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
|
||||
recordLogsEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreferenceCompat> { pref ->
|
||||
if (pref.isChecked) {
|
||||
getString(R.string.settings_advanced_record_logs_summary_enabled)
|
||||
} else {
|
||||
|
|
@ -670,7 +728,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
} else {
|
||||
getString(R.string.settings_advanced_export_logs_scrub_dialog_empty)
|
||||
}
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(title)
|
||||
.setMessage(scrubbedText)
|
||||
.setPositiveButton(R.string.settings_advanced_export_logs_scrub_dialog_button_ok) { _, _ -> /* Nothing */ }
|
||||
|
|
@ -711,7 +769,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
data class NopasteResponse(val url: String)
|
||||
}
|
||||
|
||||
class UserSettingsFragment : PreferenceFragmentCompat() {
|
||||
class UserSettingsFragment : BasePreferenceFragment() {
|
||||
private lateinit var repository: Repository
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.text.TextWatcher
|
|||
import android.view.*
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
|
@ -18,6 +19,8 @@ import io.heckel.ntfy.msg.ApiService
|
|||
import io.heckel.ntfy.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.core.view.size
|
||||
import androidx.core.view.get
|
||||
|
||||
class ShareActivity : AppCompatActivity() {
|
||||
private val repository by lazy { (application as Application).repository }
|
||||
|
|
@ -55,7 +58,24 @@ class ShareActivity : AppCompatActivity() {
|
|||
Log.d(TAG, "Create $this with intent $intent")
|
||||
|
||||
// Action bar
|
||||
val toolbarLayout = findViewById<View>(R.id.app_bar_drawer)
|
||||
val dynamicColors = repository.getDynamicColorsEnabled()
|
||||
val darkMode = isDarkThemeOn(this)
|
||||
val statusBarColor = Colors.statusBarNormal(this, dynamicColors, darkMode)
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, dynamicColors, darkMode)
|
||||
toolbarLayout.setBackgroundColor(statusBarColor)
|
||||
|
||||
val toolbar = toolbarLayout.findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||
toolbar.setTitleTextColor(toolbarTextColor)
|
||||
toolbar.setNavigationIconTint(toolbarTextColor)
|
||||
toolbar.overflowIcon?.setTint(toolbarTextColor)
|
||||
setSupportActionBar(toolbar)
|
||||
title = getString(R.string.share_title)
|
||||
|
||||
// Set system status bar color and appearance
|
||||
window.statusBarColor = statusBarColor
|
||||
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars =
|
||||
Colors.shouldUseLightStatusBar(dynamicColors, darkMode)
|
||||
|
||||
// Show 'Back' button
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
|
@ -235,6 +255,13 @@ class ShareActivity : AppCompatActivity() {
|
|||
menuInflater.inflate(R.menu.menu_share_action_bar, menu)
|
||||
this.menu = menu
|
||||
sendItem = menu.findItem(R.id.share_menu_send)
|
||||
|
||||
// Tint menu icons based on theme
|
||||
val toolbarTextColor = Colors.toolbarTextColor(this, repository.getDynamicColorsEnabled(), isDarkThemeOn(this))
|
||||
for (i in 0 until menu.size) {
|
||||
menu[i].icon?.setTint(toolbarTextColor)
|
||||
}
|
||||
|
||||
validateInput() // Disable icon
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import android.view.WindowManager
|
|||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.User
|
||||
import io.heckel.ntfy.util.AfterChangedTextWatcher
|
||||
|
|
@ -21,6 +23,7 @@ class UserFragment : DialogFragment() {
|
|||
private lateinit var baseUrlsInUse: ArrayList<String>
|
||||
private lateinit var listener: UserDialogListener
|
||||
|
||||
private lateinit var baseUrlViewLayout: TextInputLayout
|
||||
private lateinit var baseUrlView: TextInputEditText
|
||||
private lateinit var usernameView: TextInputEditText
|
||||
private lateinit var passwordView: TextInputEditText
|
||||
|
|
@ -54,9 +57,10 @@ class UserFragment : DialogFragment() {
|
|||
val view = requireActivity().layoutInflater.inflate(R.layout.fragment_user_dialog, null)
|
||||
|
||||
val positiveButtonTextResId = if (user == null) R.string.user_dialog_button_add else R.string.user_dialog_button_save
|
||||
val titleView = view.findViewById(R.id.user_dialog_title) as TextView
|
||||
val descriptionView = view.findViewById(R.id.user_dialog_description) as TextView
|
||||
val titleView = view.findViewById<TextView>(R.id.user_dialog_title)
|
||||
val descriptionView = view.findViewById<TextView>(R.id.user_dialog_description)
|
||||
|
||||
baseUrlViewLayout = view.findViewById(R.id.user_dialog_base_url_layout)
|
||||
baseUrlView = view.findViewById(R.id.user_dialog_base_url)
|
||||
usernameView = view.findViewById(R.id.user_dialog_username)
|
||||
passwordView = view.findViewById(R.id.user_dialog_password)
|
||||
|
|
@ -64,18 +68,18 @@ class UserFragment : DialogFragment() {
|
|||
if (user == null) {
|
||||
titleView.text = getString(R.string.user_dialog_title_add)
|
||||
descriptionView.text = getString(R.string.user_dialog_description_add)
|
||||
baseUrlView.visibility = View.VISIBLE
|
||||
baseUrlViewLayout.visibility = View.VISIBLE
|
||||
passwordView.hint = getString(R.string.user_dialog_password_hint_add)
|
||||
} else {
|
||||
titleView.text = getString(R.string.user_dialog_title_edit)
|
||||
descriptionView.text = getString(R.string.user_dialog_description_edit)
|
||||
baseUrlView.visibility = View.GONE
|
||||
baseUrlViewLayout.visibility = View.GONE
|
||||
usernameView.setText(user!!.username)
|
||||
passwordView.hint = getString(R.string.user_dialog_password_hint_edit)
|
||||
}
|
||||
|
||||
// Build dialog
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(view)
|
||||
.setPositiveButton(positiveButtonTextResId) { _, _ ->
|
||||
saveClicked()
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ const val ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE"
|
|||
const val ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"
|
||||
const val ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"
|
||||
|
||||
const val FEATURE_BYTES_MESSAGE = "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE"
|
||||
|
||||
const val EXTRA_APPLICATION = "application"
|
||||
const val EXTRA_PI = "pi"
|
||||
const val EXTRA_TOKEN = "token"
|
||||
const val EXTRA_ENDPOINT = "endpoint"
|
||||
const val EXTRA_MESSAGE = "message"
|
||||
|
|
|
|||
36
app/src/main/java/io/heckel/ntfy/up/LinkActivity.kt
Normal file
36
app/src/main/java/io/heckel/ntfy/up/LinkActivity.kt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package io.heckel.ntfy.up
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
|
||||
/**
|
||||
* This implements the "Select default distributor" selection for UnifiedPush.
|
||||
*
|
||||
* To test, install ntfy and another distributor (e.g. SunUp) on the same phone.
|
||||
* Install an app that uses UnifiedPush (e.g. UP Example) and click "Register".
|
||||
*
|
||||
* You should see a popup to select the default distributor.
|
||||
* See https://unifiedpush.org/developers/spec/android/#link-activity
|
||||
*/
|
||||
class LinkActivity: Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
intent?.data?.run {
|
||||
Log.d(TAG, "Received request for $callingPackage")
|
||||
val intent = Intent("org.unifiedpush.register.dummy_app")
|
||||
val pendingIntent = PendingIntent.getBroadcast(this@LinkActivity, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val result = Intent().apply {
|
||||
putExtra(EXTRA_PI, pendingIntent)
|
||||
}
|
||||
setResult(RESULT_OK, result)
|
||||
} ?: setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = LinkActivity::class.simpleName
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
package io.heckel.ntfy.util
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.text.style.*
|
||||
import android.text.util.Linkify
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.ui.Colors
|
||||
import io.noties.markwon.*
|
||||
import io.noties.markwon.core.CorePlugin
|
||||
import io.noties.markwon.core.CoreProps
|
||||
|
|
@ -36,7 +34,7 @@ internal object MarkwonFactory {
|
|||
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||
override fun configureTheme(builder: MarkwonTheme.Builder) {
|
||||
builder
|
||||
.linkColor(ContextCompat.getColor(context, R.color.teal))
|
||||
.linkColor(Colors.linkColor(context))
|
||||
.isLinkUnderlined(true)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package io.heckel.ntfy.util
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ContentResolver
|
||||
|
|
@ -20,11 +18,9 @@ import android.text.Editable
|
|||
import android.text.TextWatcher
|
||||
import android.util.Base64
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.ACTION_PROGRESS_FAILED
|
||||
import io.heckel.ntfy.db.ACTION_PROGRESS_ONGOING
|
||||
|
|
@ -68,8 +64,13 @@ fun subscriptionTopicShortUrl(subscription: Subscription) : String {
|
|||
return topicShortUrl(subscription.baseUrl, subscription.topic)
|
||||
}
|
||||
|
||||
fun displayName(subscription: Subscription) : String {
|
||||
return subscription.displayName ?: subscriptionTopicShortUrl(subscription)
|
||||
fun displayName(appBaseUrl: String?, subscription: Subscription) : String {
|
||||
if (subscription.displayName != null) {
|
||||
return subscription.displayName
|
||||
} else if (appBaseUrl == subscription.baseUrl) {
|
||||
return subscription.topic
|
||||
}
|
||||
return subscriptionTopicShortUrl(subscription)
|
||||
}
|
||||
|
||||
fun shortUrl(url: String) = url
|
||||
|
|
@ -190,11 +191,11 @@ fun decodeBytesMessage(notification: Notification): ByteArray {
|
|||
* See above; prepend emojis to title if the title is non-empty.
|
||||
* Otherwise, they are prepended to the message.
|
||||
*/
|
||||
fun formatTitle(subscription: Subscription, notification: Notification): String {
|
||||
fun formatTitle(appBaseUrl: String?, subscription: Subscription, notification: Notification): String {
|
||||
return if (notification.title != "") {
|
||||
formatTitle(notification)
|
||||
} else {
|
||||
displayName(subscription)
|
||||
displayName(appBaseUrl, subscription)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,16 +277,6 @@ data class FileInfo(
|
|||
val size: Long,
|
||||
)
|
||||
|
||||
// Status bar color fading to match action bar, see https://stackoverflow.com/q/51150077/1440785
|
||||
fun fadeStatusBarColor(window: Window, fromColor: Int, toColor: Int) {
|
||||
val statusBarColorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), fromColor, toColor)
|
||||
statusBarColorAnimation.addUpdateListener { animator ->
|
||||
val color = animator.animatedValue as Int
|
||||
window.statusBarColor = color
|
||||
}
|
||||
statusBarColorAnimation.start()
|
||||
}
|
||||
|
||||
// Generates a (cryptographically secure) random string of a certain length
|
||||
fun randomString(len: Int): String {
|
||||
val random = SecureRandom()
|
||||
|
|
@ -344,10 +335,7 @@ fun supportedImage(mimeType: String?): Boolean {
|
|||
// Play didn't grant us the permission, and F-Droid users didn't want us to have it.
|
||||
// See https://github.com/binwiederhier/ntfy/issues/531 & https://github.com/binwiederhier/ntfy/issues/684
|
||||
fun canOpenAttachment(attachment: Attachment?): Boolean {
|
||||
if (attachment?.type == ANDROID_APP_MIME_TYPE) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return attachment?.type != ANDROID_APP_MIME_TYPE
|
||||
}
|
||||
|
||||
// Check if battery optimization is enabled, see https://stackoverflow.com/a/49098293/1440785
|
||||
|
|
@ -507,11 +495,10 @@ fun Button.dangerButton(context: Context) {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setTextAppearance(R.style.DangerText)
|
||||
} else {
|
||||
setTextColor(ContextCompat.getColor(context, Colors.dangerText(context)))
|
||||
setTextColor(Colors.dangerText(context))
|
||||
}
|
||||
}
|
||||
|
||||
fun Long.nullIfZero(): Long? {
|
||||
return if (this == 0L) return null else this
|
||||
}
|
||||
|
||||
|
|
|
|||
9
app/src/main/res/anim/slide_in_bottom.xml
Normal file
9
app/src/main/res/anim/slide_in_bottom.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/decelerate_cubic">
|
||||
<translate
|
||||
android:duration="300"
|
||||
android:fromYDelta="100%"
|
||||
android:toYDelta="0" />
|
||||
</set>
|
||||
|
||||
9
app/src/main/res/anim/slide_out_bottom.xml
Normal file
9
app/src/main/res/anim/slide_out_bottom.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/accelerate_cubic">
|
||||
<translate
|
||||
android:duration="250"
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="100%" />
|
||||
</set>
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
|
|
|||
11
app/src/main/res/drawable/ic_close_white_24dp.xml
Normal file
11
app/src/main/res/drawable/ic_close_white_24dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -1,12 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.DetailActivity"
|
||||
>
|
||||
<include
|
||||
android:id="@+id/app_bar_drawer"
|
||||
layout="@layout/app_bar_drawer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/detail_content_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@color/detail_activity_background"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
style="@style/CardViewBackground"
|
||||
android:id="@+id/detail_notification_list_container"
|
||||
|
|
@ -73,4 +88,6 @@
|
|||
android:autoLink="web"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -1,290 +1,309 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:shapeAppearance="?shapeAppearanceLargeComponent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:id="@+id/main_banner_battery"
|
||||
android:visibility="visible"
|
||||
>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_battery_constraint" android:elevation="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_battery_alert_red_24dp"
|
||||
android:id="@+id/main_banner_battery_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_battery_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_battery_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_battery_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_battery_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_battery_image"
|
||||
android:layout_marginStart="10dp"/>
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_battery_ask_later,main_banner_battery_dontaskagain,main_banner_battery_fix_now"
|
||||
app:layout_constraintTop_toBottomOf="@id/main_banner_battery_text"
|
||||
app:flow_horizontalAlign="end"
|
||||
app:flow_wrapMode="chain"
|
||||
app:flow_horizontalStyle="packed"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:id="@+id/main_banner_battery_flow"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginStart="15dp"
|
||||
app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_ask_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_remind_later"
|
||||
tools:layout_editor_absoluteX="15dp" tools:layout_editor_absoluteY="67dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_dismiss"
|
||||
tools:layout_editor_absoluteX="142dp" tools:layout_editor_absoluteY="71dp"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_fix_now"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_fix_now"
|
||||
tools:layout_editor_absoluteX="269dp" tools:layout_editor_absoluteY="67dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:shapeAppearance="?shapeAppearanceLargeComponent" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_banner_battery"
|
||||
android:id="@+id/main_banner_websocket" android:visibility="visible">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_websocket_constraint" android:elevation="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_announcement_orange_24dp"
|
||||
android:id="@+id/main_banner_websocket_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_websocket_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_websocket_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_websocket_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_websocket_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_websocket_image"
|
||||
android:layout_marginStart="10dp"
|
||||
/>
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_websocket_remind_later,main_banner_websocket_dontaskagain,main_banner_websocket_enable" app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_remind_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_remind_later"
|
||||
tools:layout_editor_absoluteX="86dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_dismiss"
|
||||
tools:layout_editor_absoluteX="260dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_enable"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_enable_now"
|
||||
tools:layout_editor_absoluteX="253dp" tools:layout_editor_absoluteY="131dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<include
|
||||
android:id="@+id/app_bar_drawer"
|
||||
layout="@layout/app_bar_drawer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:shapeAppearance="?shapeAppearanceLargeComponent" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_banner_websocket"
|
||||
android:id="@+id/main_banner_websocket_reconnect" android:visibility="visible">
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_websocket_reconnect_constraint" android:elevation="5dp">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_announcement_orange_24dp"
|
||||
android:id="@+id/main_banner_websocket_reconnect_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_websocket_reconnect_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_websocket_reconnect_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_websocket_reconnect_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_websocket_reconnect_text"
|
||||
android:layout_width="0dp"
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
style="@style/BannerCardStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_websocket_reconnect_image"
|
||||
android:layout_marginStart="10dp"
|
||||
android:id="@+id/main_banner_battery"
|
||||
android:visibility="visible"
|
||||
>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_battery_constraint" android:elevation="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_battery_alert_red_24dp"
|
||||
android:id="@+id/main_banner_battery_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_battery_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_battery_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_battery_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_battery_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_battery_image"
|
||||
android:layout_marginStart="10dp"/>
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_battery_ask_later,main_banner_battery_dontaskagain,main_banner_battery_fix_now"
|
||||
app:layout_constraintTop_toBottomOf="@id/main_banner_battery_text"
|
||||
app:flow_horizontalAlign="end"
|
||||
app:flow_wrapMode="chain"
|
||||
app:flow_horizontalStyle="packed"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:id="@+id/main_banner_battery_flow"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginStart="15dp"
|
||||
app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_ask_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_remind_later"
|
||||
tools:layout_editor_absoluteX="15dp" tools:layout_editor_absoluteY="67dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_dismiss"
|
||||
tools:layout_editor_absoluteX="142dp" tools:layout_editor_absoluteY="71dp"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_battery_fix_now"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_battery_button_fix_now"
|
||||
tools:layout_editor_absoluteX="269dp" tools:layout_editor_absoluteY="67dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/BannerCardStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_banner_battery"
|
||||
android:id="@+id/main_banner_websocket" android:visibility="visible">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_websocket_constraint" android:elevation="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_announcement_orange_24dp"
|
||||
android:id="@+id/main_banner_websocket_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_websocket_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_websocket_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_websocket_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_websocket_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_websocket_image"
|
||||
android:layout_marginStart="10dp"
|
||||
/>
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_websocket_reconnect_remind_later,main_banner_websocket_reconnect_dontaskagain,main_banner_websocket_reconnect_enable" app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_reconnect_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow_reconnect" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_websocket_remind_later,main_banner_websocket_dontaskagain,main_banner_websocket_enable" app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_remind_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_remind_later"
|
||||
tools:layout_editor_absoluteX="86dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_remind_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_remind_later"
|
||||
tools:layout_editor_absoluteX="86dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_dismiss"
|
||||
tools:layout_editor_absoluteX="260dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_dismiss"
|
||||
tools:layout_editor_absoluteX="260dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_enable"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_enable_now"
|
||||
tools:layout_editor_absoluteX="253dp" tools:layout_editor_absoluteY="131dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_enable"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_button_enable_now"
|
||||
tools:layout_editor_absoluteX="253dp" tools:layout_editor_absoluteY="131dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/main_subscriptions_list_container"
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_reconnect">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/main_subscriptions_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:clipToPadding="false"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:layoutManager="LinearLayoutManager"/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fab" app:layout_constraintStart_toStartOf="parent"
|
||||
android:id="@+id/main_no_subscriptions" android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_sms_gray_48dp"
|
||||
android:id="@+id/main_no_subscriptions_image"/>
|
||||
<TextView
|
||||
android:id="@+id/main_no_subscriptions_text"
|
||||
android:text="@string/main_no_subscriptions_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:padding="10dp" android:gravity="center_horizontal"
|
||||
android:paddingStart="50dp" android:paddingEnd="50dp"/>
|
||||
<TextView
|
||||
android:text="@string/main_how_to_intro"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_how_to_intro"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"/>
|
||||
<TextView
|
||||
android:text="@string/main_how_to_link"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_how_to_link"
|
||||
android:layout_marginTop="7dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:linksClickable="true"
|
||||
android:autoLink="web"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="24dp"
|
||||
android:contentDescription="@string/main_add_button_description"
|
||||
android:src="@drawable/ic_add_black_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/FloatingActionButton"
|
||||
/>
|
||||
style="@style/BannerCardStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_banner_websocket"
|
||||
android:id="@+id/main_banner_websocket_reconnect" android:visibility="visible">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_banner_websocket_reconnect_constraint" android:elevation="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp" app:srcCompat="@drawable/ic_announcement_orange_24dp"
|
||||
android:id="@+id/main_banner_websocket_reconnect_image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_banner_websocket_reconnect_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/main_banner_websocket_reconnect_text"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/main_banner_websocket_reconnect_text"
|
||||
android:layout_marginStart="15dp"/>
|
||||
<TextView
|
||||
android:id="@+id/main_banner_websocket_reconnect_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/main_banner_websocket_reconnect_image"
|
||||
android:layout_marginStart="10dp"
|
||||
/>
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:constraint_referenced_ids="main_banner_websocket_reconnect_remind_later,main_banner_websocket_reconnect_dontaskagain,main_banner_websocket_reconnect_enable" app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_reconnect_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow_reconnect" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
|
||||
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_remind_later"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_remind_later"
|
||||
tools:layout_editor_absoluteX="86dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_dontaskagain"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_dismiss"
|
||||
tools:layout_editor_absoluteX="260dp" tools:layout_editor_absoluteY="83dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/main_banner_websocket_reconnect_enable"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_banner_websocket_reconnect_button_enable_now"
|
||||
tools:layout_editor_absoluteX="253dp" tools:layout_editor_absoluteY="131dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/main_subscriptions_list_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_reconnect">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/main_subscriptions_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:clipToPadding="false"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:layoutManager="LinearLayoutManager"/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fab" app:layout_constraintStart_toStartOf="parent"
|
||||
android:id="@+id/main_no_subscriptions" android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_sms_gray_48dp"
|
||||
android:id="@+id/main_no_subscriptions_image"/>
|
||||
<TextView
|
||||
android:id="@+id/main_no_subscriptions_text"
|
||||
android:text="@string/main_no_subscriptions_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:padding="10dp" android:gravity="center_horizontal"
|
||||
android:paddingStart="50dp" android:paddingEnd="50dp"/>
|
||||
<TextView
|
||||
android:text="@string/main_how_to_intro"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_how_to_intro"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"/>
|
||||
<TextView
|
||||
android:text="@string/main_how_to_link"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/main_how_to_link"
|
||||
android:layout_marginTop="7dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:linksClickable="true"
|
||||
android:autoLink="web"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="24dp"
|
||||
android:contentDescription="@string/main_add_button_description"
|
||||
android:src="@drawable/ic_add_black_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/FloatingActionButton"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,27 @@
|
|||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include
|
||||
android:id="@+id/app_bar_drawer"
|
||||
layout="@layout/app_bar_drawer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settings_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<include
|
||||
android:id="@+id/app_bar_drawer"
|
||||
layout="@layout/app_bar_drawer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -40,6 +54,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/share_content_text_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:lines="10" android:gravity="start|top" app:layout_constraintTop_toBottomOf="@id/share_content_image" android:minLines="1" android:layout_marginTop="5dp"/>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -86,6 +101,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/add_dialog_topic_name_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:maxLines="1" android:inputType="text|textNoSuggestions" android:maxLength="64"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/share_topic_title" android:layout_marginStart="-3dp"/>
|
||||
|
|
@ -163,4 +179,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/share_error_text" android:layout_marginTop="2dp"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
17
app/src/main/res/layout/app_bar_drawer.xml
Normal file
17
app/src/main/res/layout/app_bar_drawer.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:fitsSystemWindows="true"
|
||||
app:liftOnScroll="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
|
@ -1,73 +1,121 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/add_dialog_subscribe_view">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="@string/add_dialog_title"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:id="@+id/add_dialog_subscribe_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/add_dialog_subscribe_description"
|
||||
android:indeterminate="true" android:layout_marginBottom="5dp" android:visibility="gone"/>
|
||||
<TextView
|
||||
android:text="@string/add_dialog_description_below"
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/add_dialog_app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
app:elevation="0dp"
|
||||
app:liftOnScroll="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/add_dialog_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorSurface"
|
||||
app:navigationIcon="@drawable/ic_close_white_24dp"
|
||||
app:navigationIconTint="?attr/colorOnSurface"
|
||||
app:title="@string/add_dialog_title"
|
||||
app:titleTextColor="?attr/colorOnSurface"
|
||||
app:menu="@menu/menu_add_dialog" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="?dialogPreferredPadding"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/add_dialog_subscribe_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_description"
|
||||
android:paddingStart="4dp" android:paddingTop="3dp" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_title"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_subscribe_topic_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/add_dialog_topic_name_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="text" android:maxLength="64"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_description"/>
|
||||
<CheckBox
|
||||
android:text="@string/add_dialog_use_another_server"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_use_another_server_checkbox"
|
||||
android:layout_marginStart="-3dp" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_topic_text"
|
||||
android:layout_marginTop="-3dp"/>
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_description"
|
||||
android:text="@string/add_dialog_description_below"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingTop="16dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:id="@+id/add_dialog_subscribe_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:indeterminate="true"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/add_dialog_subscribe_topic_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_description"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_subscribe_topic_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/add_dialog_topic_name_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1"
|
||||
android:inputType="text"
|
||||
android:maxLength="64"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/add_dialog_subscribe_use_another_server_checkbox"
|
||||
android:text="@string/add_dialog_use_another_server"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="-3dp"
|
||||
android:layout_marginTop="-3dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_topic_layout"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_use_another_server_description"
|
||||
android:text="@string/add_dialog_use_another_server_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_use_another_server_description"
|
||||
android:paddingStart="4dp" android:paddingTop="0dp"
|
||||
android:visibility="gone" app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-5dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingTop="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_use_another_server_checkbox"
|
||||
android:layout_marginTop="-5dp"/>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_use_another_server_checkbox" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense.ExposedDropdownMenu"
|
||||
android:id="@+id/add_dialog_subscribe_base_url_layout"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -81,13 +129,14 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_use_another_server_description">
|
||||
<AutoCompleteTextView
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/add_dialog_subscribe_base_url_text"
|
||||
android:hint="@string/app_base_url"
|
||||
android:maxLines="1"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:inputType="textNoSuggestions"
|
||||
android:paddingStart="0dp"
|
||||
|
|
@ -96,132 +145,196 @@
|
|||
android:paddingBottom="5dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_instant_delivery_box"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_base_url_layout" android:layout_marginTop="-3dp">
|
||||
<CheckBox
|
||||
android:text="@string/add_dialog_instant_delivery"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_instant_delivery_checkbox"
|
||||
android:layout_marginTop="-8dp" android:layout_marginBottom="-5dp"
|
||||
android:layout_marginStart="-3dp"/>
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp" app:srcCompat="@drawable/ic_bolt_gray_24dp"
|
||||
android:id="@+id/add_dialog_subscribe_instant_image"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_item_text"
|
||||
app:layout_constraintEnd_toStartOf="@+id/main_item_date" android:paddingTop="3dp"
|
||||
android:layout_marginTop="3dp"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/add_dialog_subscribe_instant_delivery_box"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-3dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_base_url_layout">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/add_dialog_subscribe_instant_delivery_checkbox"
|
||||
android:text="@string/add_dialog_instant_delivery"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-8dp"
|
||||
android:layout_marginBottom="-5dp"
|
||||
android:layout_marginStart="-3dp"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:paddingTop="3dp"
|
||||
android:id="@+id/add_dialog_subscribe_instant_image"
|
||||
app:srcCompat="@drawable/ic_bolt_gray_24dp"
|
||||
app:layout_constraintTop_toTopOf="@+id/main_item_text"
|
||||
app:layout_constraintEnd_toStartOf="@+id/main_item_date"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_instant_delivery_description"
|
||||
android:text="@string/add_dialog_instant_delivery_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_instant_delivery_description"
|
||||
android:paddingStart="4dp" android:paddingTop="0dp"
|
||||
android:visibility="gone" app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingTop="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_instant_delivery_box"/>
|
||||
<TextView
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_foreground_description"
|
||||
android:text="@string/add_dialog_foreground_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_foreground_description"
|
||||
android:paddingStart="4dp" app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_instant_delivery_description"/>
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp" app:srcCompat="@drawable/ic_error_red_24dp"
|
||||
android:id="@+id/add_dialog_subscribe_error_text_image"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/add_dialog_subscribe_error_text" android:layout_marginTop="1dp"/>
|
||||
<TextView
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/add_dialog_subscribe_error_text_image"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="1dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_error_red_24dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/add_dialog_subscribe_error_text"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_error_text"
|
||||
android:text="Unable to resolve host example.com"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_error_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:paddingStart="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_foreground_description"
|
||||
android:paddingEnd="4dp"
|
||||
android:textAppearance="@style/DangerText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_foreground_description"
|
||||
app:layout_constraintStart_toEndOf="@id/add_dialog_subscribe_error_text_image"
|
||||
android:layout_marginTop="5dp"
|
||||
tools:visibility="gone"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
<ScrollView
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/add_dialog_login_view">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_login_title"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/add_dialog_login_view"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="@string/add_dialog_login_title"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
<TextView
|
||||
android:text="@string/add_dialog_login_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_login_description"
|
||||
android:paddingStart="4dp" android:paddingTop="3dp" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_title" android:paddingEnd="4dp"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_login_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/add_dialog_login_username_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="text" android:maxLength="64"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="10dp" app:layout_constraintTop_toBottomOf="@+id/add_dialog_login_description"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_login_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/add_dialog_login_password_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="textPassword" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_username"/>
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp" app:srcCompat="@drawable/ic_error_red_24dp"
|
||||
android:id="@+id/add_dialog_login_error_text_image"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="@+id/add_dialog_login_error_text" app:layout_constraintTop_toTopOf="@+id/add_dialog_login_error_text"/>
|
||||
<TextView
|
||||
android:text="Login failed. User not authorized."
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_login_error_text"
|
||||
android:paddingStart="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_password"
|
||||
android:paddingEnd="4dp"
|
||||
android:textAppearance="@style/DangerText"
|
||||
app:layout_constraintStart_toEndOf="@id/add_dialog_login_error_text_image"/>
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:id="@+id/add_dialog_login_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/add_dialog_login_description"
|
||||
android:indeterminate="true" android:layout_marginBottom="5dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:text="@string/add_dialog_login_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/add_dialog_login_description"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:id="@+id/add_dialog_login_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:indeterminate="true"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/add_dialog_login_username_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/add_dialog_login_description"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_login_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/add_dialog_login_username_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1"
|
||||
android:inputType="text"
|
||||
android:maxLength="64"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/add_dialog_login_password_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_username_layout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_login_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/add_dialog_login_password_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1"
|
||||
android:inputType="textPassword"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:id="@+id/add_dialog_login_error_text_image"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_error_red_24dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/add_dialog_login_error_text"
|
||||
app:layout_constraintTop_toTopOf="@+id/add_dialog_login_error_text"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_login_error_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Login failed. User not authorized."
|
||||
android:paddingStart="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_password_layout"
|
||||
android:paddingEnd="4dp"
|
||||
android:visibility="gone"
|
||||
android:textAppearance="@style/DangerText"
|
||||
app:layout_constraintStart_toEndOf="@id/add_dialog_login_error_text_image"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -1,55 +1,93 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:visibility="visible" android:paddingBottom="10dp">
|
||||
<TextView
|
||||
android:text="This topic requires you to login. Please pick an existing user or type in a username and password."
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/user_dialog_description"
|
||||
android:paddingStart="4dp" android:paddingTop="3dp" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/user_dialog_title"/>
|
||||
<TextView
|
||||
android:id="@+id/user_dialog_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="@string/user_dialog_title_add"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="?dialogPreferredPadding"
|
||||
android:visibility="visible">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
<TextView
|
||||
android:id="@+id/user_dialog_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="@string/user_dialog_title_add"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_dialog_description"
|
||||
android:text="@string/add_dialog_login_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="?dialogPreferredPadding"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/user_dialog_title"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/user_dialog_base_url_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/user_dialog_description"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/user_dialog_base_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/user_dialog_base_url_hint"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/user_dialog_base_url_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="text"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp" app:layout_constraintTop_toBottomOf="@id/user_dialog_description"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:maxLines="1"
|
||||
android:inputType="text"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/user_dialog_username_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/user_dialog_base_url_layout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/user_dialog_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/user_dialog_username_hint"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/user_dialog_username_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="text"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp" app:layout_constraintTop_toBottomOf="@id/user_dialog_base_url"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:maxLines="1"
|
||||
android:inputType="text"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/user_dialog_username_layout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/user_dialog_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/user_dialog_password_hint_add"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/user_dialog_password_hint_add"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="textPassword"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="6dp" app:layout_constraintTop_toBottomOf="@id/user_dialog_username"/>
|
||||
android:maxLines="1"
|
||||
android:inputType="textPassword"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -45,15 +45,18 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
<EditText
|
||||
android:id="@android:id/edit"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight = "48dp" />
|
||||
android:layout_marginHorizontal="?dialogPreferredPadding"
|
||||
android:paddingTop="?dialogPreferredPadding">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@android:id/edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
|
|||
5
app/src/main/res/layout/view_preference_switch.xml
Normal file
5
app/src/main/res/layout/view_preference_switch.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/switchWidget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
10
app/src/main/res/menu/menu_add_dialog.xml
Normal file
10
app/src/main/res/menu/menu_add_dialog.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/add_dialog_action_button"
|
||||
android:title="@string/add_dialog_button_subscribe"
|
||||
android:enabled="false"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
|
||||
|
|
@ -1,17 +1,44 @@
|
|||
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/detail_menu_notifications_enabled" android:title="@string/detail_menu_notifications_enabled"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_white_24dp"/>
|
||||
<item android:id="@+id/detail_menu_notifications_disabled_until" android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"/>
|
||||
<item android:id="@+id/detail_menu_notifications_disabled_forever" android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_white_outline_24dp"/>
|
||||
<item android:id="@+id/detail_menu_enable_instant" android:title="@string/detail_menu_enable_instant"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_bolt_outline_white_24dp"/>
|
||||
<item android:id="@+id/detail_menu_disable_instant" android:title="@string/detail_menu_disable_instant"
|
||||
android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom"/>
|
||||
<item android:id="@+id/detail_menu_settings" android:title="@string/detail_menu_settings"/>
|
||||
<item android:id="@+id/detail_menu_copy_url" android:title="@string/detail_menu_copy_url"/>
|
||||
<item android:id="@+id/detail_menu_clear" android:title="@string/detail_menu_clear"/>
|
||||
<item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/>
|
||||
<item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/detail_menu_notifications_enabled"
|
||||
android:icon="@drawable/ic_notifications_white_24dp"
|
||||
android:title="@string/detail_menu_notifications_enabled"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_notifications_disabled_until"
|
||||
android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"
|
||||
android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_notifications_disabled_forever"
|
||||
android:icon="@drawable/ic_notifications_off_white_outline_24dp"
|
||||
android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_enable_instant"
|
||||
android:icon="@drawable/ic_bolt_outline_white_24dp"
|
||||
android:title="@string/detail_menu_enable_instant"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_disable_instant"
|
||||
android:icon="@drawable/ic_bolt_white_24dp"
|
||||
android:title="@string/detail_menu_disable_instant"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_settings"
|
||||
android:title="@string/detail_menu_settings" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_copy_url"
|
||||
android:title="@string/detail_menu_copy_url" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_clear"
|
||||
android:title="@string/detail_menu_clear" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_test"
|
||||
android:title="@string/detail_menu_test" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_unsubscribe"
|
||||
android:title="@string/detail_menu_unsubscribe" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/detail_action_mode_copy" android:title="@string/detail_action_mode_menu_copy"
|
||||
android:icon="@drawable/ic_content_copy_white_24dp"/>
|
||||
<item android:id="@+id/detail_action_mode_delete" android:title="@string/detail_action_mode_menu_delete"
|
||||
android:icon="@drawable/ic_delete_white_20dp"/>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/detail_action_mode_copy"
|
||||
android:icon="@drawable/ic_content_copy_white_24dp"
|
||||
android:title="@string/detail_action_mode_menu_copy"
|
||||
app:iconTint="@android:color/white" />
|
||||
<item
|
||||
android:id="@+id/detail_action_mode_delete"
|
||||
android:icon="@drawable/ic_delete_white_20dp"
|
||||
android:title="@string/detail_action_mode_menu_delete"
|
||||
app:iconTint="@android:color/white" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,31 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/main_menu_notifications_enabled" android:title="@string/main_menu_notifications_enabled"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_white_24dp"/>
|
||||
<item android:id="@+id/main_menu_notifications_disabled_until" android:title="@string/main_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"/>
|
||||
<item android:id="@+id/main_menu_notifications_disabled_forever" android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_white_outline_24dp"/>
|
||||
<item android:id="@+id/main_menu_settings" android:title="@string/main_menu_settings_title"/>
|
||||
<item android:id="@+id/main_menu_docs" android:title="@string/main_menu_docs_title"/>
|
||||
<item android:id="@+id/main_menu_rate" android:title="@string/main_menu_rate_title"/>
|
||||
<item android:id="@+id/main_menu_donate" android:title="@string/main_menu_donate_title"/>
|
||||
<item android:id="@+id/main_menu_report_bug" android:title="@string/main_menu_report_bug_title"/>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/main_menu_notifications_enabled"
|
||||
android:icon="@drawable/ic_notifications_white_24dp"
|
||||
android:title="@string/main_menu_notifications_enabled"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/main_menu_notifications_disabled_until"
|
||||
android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"
|
||||
android:title="@string/main_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/main_menu_notifications_disabled_forever"
|
||||
android:icon="@drawable/ic_notifications_off_white_outline_24dp"
|
||||
android:title="@string/detail_menu_notifications_disabled_forever"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/main_menu_settings"
|
||||
android:title="@string/main_menu_settings_title" />
|
||||
<item
|
||||
android:id="@+id/main_menu_docs"
|
||||
android:title="@string/main_menu_docs_title" />
|
||||
<item
|
||||
android:id="@+id/main_menu_rate"
|
||||
android:title="@string/main_menu_rate_title" />
|
||||
<item
|
||||
android:id="@+id/main_menu_report_bug"
|
||||
android:title="@string/main_menu_report_bug_title" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/main_action_mode_delete" android:title="@string/main_action_mode_menu_unsubscribe"
|
||||
android:icon="@drawable/ic_delete_white_20dp"/>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/main_action_mode_delete"
|
||||
android:icon="@drawable/ic_delete_white_20dp"
|
||||
android:title="@string/main_action_mode_menu_unsubscribe"
|
||||
app:iconTint="@android:color/white" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/share_menu_send" android:title="@string/share_menu_send"
|
||||
app:showAsAction="always" android:icon="@drawable/ic_send_white_24dp"/>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/share_menu_send"
|
||||
android:icon="@drawable/ic_send_white_24dp"
|
||||
android:title="@string/share_menu_send"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@
|
|||
<string name="refresh_message_no_results">كل شئ محدث لاخر تحديث</string>
|
||||
<string name="channel_subscriber_notification_instant_text_one">تم الاشتراك في 1 موضوع فوري</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">تم الاشتراك في 4 مواضيع فورية</string>
|
||||
<string name="main_menu_donate_title">تبرع 💸</string>
|
||||
<string name="settings_title">اﻹعدادات</string>
|
||||
<string name="refresh_message_error">تعذر تحديث %1$d اشتراكات
|
||||
\n
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="detail_settings_about_header">Относно</string>
|
||||
<string name="detail_settings_about_topic_url_title">Адрес на темата</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Копирано в междинната памет</string>
|
||||
<string name="main_menu_donate_title">Даряване 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Ntfy не може да инсталира получени приложения. Вместо това изтеглете чрез браузъра. За подробности вижте дефект №531.</string>
|
||||
<string name="channel_notifications_group_default_name">Подразбирани</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_title">Потребителски настройки за известия</string>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
<string name="channel_notifications_high_name">Prioritat alta</string>
|
||||
<string name="channel_notifications_max_name">Prioritat màxima</string>
|
||||
<string name="channel_subscriber_service_name">Servei Subscripció</string>
|
||||
<string name="main_menu_donate_title">Donar 💸</string>
|
||||
<string name="main_item_status_reconnecting">reconnectant…</string>
|
||||
<string name="channel_subscriber_notification_title">Escoltant notificacions entrants</string>
|
||||
<string name="channel_subscriber_notification_instant_text">Subscrit per entrega instantània de temes</string>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="main_banner_websocket_button_enable_now">Povolit nyní</string>
|
||||
<string name="main_banner_websocket_text">WebSockets jsou doporučenou metodou připojení k vašemu serveru, která může zlepšit zvýšit výdrž baterie, ale může vyžadovat <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">další konfiguraci v proxy serveru</a>. Metodu připojení lze přepnout v Nastavení.</string>
|
||||
<string name="add_dialog_base_urls_dropdown_choose">Zvolit URL služby</string>
|
||||
<string name="main_menu_donate_title">Přispět 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Aplikace již nelze nainstalovat. Místo toho stahujte přes prohlížeč. Podrobnosti naleznete v issue #531.</string>
|
||||
<string name="channel_notifications_group_default_name">Výchozí</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">Upozornění s nejvyšší prioritou pouze jednou</string>
|
||||
|
|
|
|||
9
app/src/main/res/values-cu/strings.xml
Normal file
9
app/src/main/res/values-cu/strings.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="channel_notifications_low_name">Низкое преимѹ́щество</string>
|
||||
<string name="channel_notifications_min_name">Мин преимѹ́щество</string>
|
||||
<string name="channel_subscriber_service_name">Слꙋ́жба подписки</string>
|
||||
<string name="channel_notifications_default_name">Ѻбыденное преимѹ́щество</string>
|
||||
<string name="channel_notifications_high_name">Высо́кое преимѹ́щество</string>
|
||||
<string name="channel_notifications_max_name">Макс преимѹ́щество</string>
|
||||
</resources>
|
||||
|
|
@ -17,4 +17,81 @@
|
|||
<string name="channel_subscriber_notification_instant_text_one">Abonnerer på et emne med øjeblikkelig levering</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">Abonnerer på fire emner med øjeblikkelig levering</string>
|
||||
<string name="channel_notifications_high_name">Høj prioritet</string>
|
||||
</resources>
|
||||
<string name="channel_subscriber_notification_noinstant_text_one">Abonnerer på et emne</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_two">Abonnerer på to emner</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_three">Abonnerer på tre emner</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_four">Abonnerer på fire emner</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_five">Abonnerer på fem emner</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_six">Abonnerer på seks emner</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_more">Abonnerer på %1$d emner</string>
|
||||
<string name="refresh_message_result">%1$d notifikation(er) modtaget</string>
|
||||
<string name="refresh_message_no_results">Alt er opdateret</string>
|
||||
<string name="refresh_message_error">Kunne ikke opdaterer %1$d abonnementer\n\n%2$s</string>
|
||||
<string name="refresh_message_error_one">Kunne ikke genopfriske abonnement %1$s</string>
|
||||
<string name="main_menu_notifications_enabled">Notifikationer aktiveret</string>
|
||||
<string name="main_menu_notifications_disabled_forever">Notifikationer slået fra</string>
|
||||
<string name="main_menu_notifications_disabled_until">Notifikationer slået fra indtil %1$s</string>
|
||||
<string name="main_menu_settings_title">Indstillinger</string>
|
||||
<string name="main_menu_report_bug_title">Anmeld fejl</string>
|
||||
<string name="main_menu_docs_title">Læs manualen</string>
|
||||
<string name="main_menu_rate_title">Anmeld appen ⭐</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">Afmeld</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Afmeld valgte emne(r) og slet alle notifikationer permanent?</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Slet permanent</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Annuller</string>
|
||||
<string name="main_item_status_text_one">%1$d notifikationer</string>
|
||||
<string name="main_item_status_text_not_one">%1$d notifikationer</string>
|
||||
<string name="main_item_status_reconnecting">Tilslutter …</string>
|
||||
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
|
||||
<string name="main_item_date_yesterday">i går</string>
|
||||
<string name="main_add_button_description">Tilføj abonomment</string>
|
||||
<string name="main_no_subscriptions_text">Det ser ud til at du ikke abonnere på noget endnu.</string>
|
||||
<string name="main_how_to_intro">Klik + for at oprette eller abonnere på et emne. Derefter kan du modtage notifikationer på din enhed vha. PUT og POST.</string>
|
||||
<string name="main_how_to_link">Detaljeret instruktioner tilgængelige på ntfy.sh, og i manualen.</string>
|
||||
<string name="main_unified_push_toast">Dette abonnement er styret af %1$s vha. UnifiedPush</string>
|
||||
<string name="main_banner_battery_text">Batterioptimering bør være slået fra for appen for at undgå problemer med at modtage notifikationer.</string>
|
||||
<string name="main_banner_battery_button_remind_later">Spørg senere</string>
|
||||
<string name="main_banner_battery_button_dismiss">Afvis</string>
|
||||
<string name="main_banner_battery_button_fix_now">Løs nu</string>
|
||||
<string name="main_banner_websocket_text">Anvendelse af WebSockets er den anbefalede måde tilslutte dig din server, og kan forbedre batterilevetiden, men det kan kræve <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">yderligere konfigurationer i din proxy</a>. Dette kan ændres i indstillingerne.</string>
|
||||
<string name="main_banner_websocket_button_remind_later">Spørg senere</string>
|
||||
<string name="main_banner_websocket_button_dismiss">Afvis</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Aktiver nu</string>
|
||||
<string name="main_banner_websocket_reconnect_text">For at kunne garantere at WebSockets genopretter forbindelsen i baggrunden, skal du give Alarm & Påmindelses tilladelser til ntfy</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Spørg senere</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Afvis</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Tildel nu</string>
|
||||
<string name="add_dialog_title">Abonner på emne</string>
|
||||
<string name="add_dialog_description_below">Emner er ikke password-beskyttet, så vælg et navn der er svært at gætte. Når først du er abonnere, kan du PUT/POST notifikationer.</string>
|
||||
<string name="add_dialog_topic_name_hint">Emne navn, f.eks. jørns_alarmer</string>
|
||||
<string name="add_dialog_use_another_server">Brug anden server</string>
|
||||
<string name="add_dialog_use_another_server_description">Skriv URLs herunder for at abonnere på emner fra andre servere.</string>
|
||||
<string name="add_dialog_instant_delivery">Øjeblikkelig levering i dvale</string>
|
||||
<string name="add_dialog_instant_delivery_description">Garanter at meldingerne bliver leveret med det samme, selv hvis enheden er inaktiv.</string>
|
||||
<string name="add_dialog_foreground_description">Øjeblikkelig levering er altid aktiveret for andre værter end %1$s.</string>
|
||||
<string name="add_dialog_button_cancel">Annuller</string>
|
||||
<string name="add_dialog_button_subscribe">Abonner</string>
|
||||
<string name="add_dialog_button_back">Tilbage</string>
|
||||
<string name="add_dialog_button_login">Log ind</string>
|
||||
<string name="add_dialog_error_connection_failed">Tilslutning fejlede: %1$s</string>
|
||||
<string name="add_dialog_login_title">Login krævet</string>
|
||||
<string name="add_dialog_login_description">Dette emne kræver at du logger ind. Skriv venligst dit brugernavn og password.</string>
|
||||
<string name="add_dialog_login_username_hint">Brugernavn</string>
|
||||
<string name="add_dialog_login_password_hint">Password</string>
|
||||
<string name="add_dialog_login_error_not_authorized">Login fejlede. Bruger %1$s er ikke autoriseret.</string>
|
||||
<string name="add_dialog_login_new_user">Ny bruger</string>
|
||||
<string name="add_dialog_base_urls_dropdown_choose">Vælg service URL</string>
|
||||
<string name="add_dialog_base_urls_dropdown_clear">Fjern service URL</string>
|
||||
<string name="detail_no_notifications_text">Du har ikke modtaget nogen notifikationer for dette emne endnu.</string>
|
||||
<string name="detail_how_to_intro">For at sende notifikationer for dette emne, PUT eller POST til emne URLen.</string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Example (using curl):<br/><tt>$ curl -d \"Hej\"%1$s</tt>]]></string>
|
||||
<string name="detail_how_to_link">Detaljeret instruktioner tilgængelig på ntfy.sh, and in the docs.</string>
|
||||
<string name="detail_clear_dialog_message">Slet alle notifikationer for emnet?</string>
|
||||
<string name="detail_clear_dialog_permanently_delete">Slet permanent</string>
|
||||
<string name="detail_clear_dialog_cancel">Annuller</string>
|
||||
<string name="detail_delete_dialog_message">Afmeld abonnementet for dette emne og slet alle modtagende notifikationer?</string>
|
||||
<string name="detail_delete_dialog_permanently_delete">Slet permanent</string>
|
||||
<string name="detail_delete_dialog_cancel">Annuller</string>
|
||||
<string name="detail_test_title">Test: Ændre titlen til det du vil.</string>
|
||||
<string name="detail_test_message">Dette er en test notifikation fra ntfy Android app. Den har prioritets niveau %1$d. Hvis du sender en anden, kan den se anderledes ud.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="detail_settings_about_topic_url_title">Themen-URL</string>
|
||||
<string name="detail_settings_about_header">Über</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">In Zwischenablage kopiert</string>
|
||||
<string name="main_menu_donate_title">Spenden 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Apps können nicht mehr installiert werden. Bitte stattdessen über einen Browser herunterladen. Details siehe Issue #531.</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_on">Eigene Einstellungen für dieses Abo verwenden</string>
|
||||
<string name="detail_settings_notifications_open_channels_title">Beanchrichtigungseinstellungen konfigurieren</string>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@
|
|||
<string name="add_dialog_topic_name_hint">Όνομα θέματος</string>
|
||||
<string name="add_dialog_use_another_server">Χρήση άλλου server/εξυπηρετητή</string>
|
||||
<string name="add_dialog_title">Εγγραφή σε ειδοποίηση</string>
|
||||
<string name="main_menu_donate_title">Κάντε δωρεά</string>
|
||||
<string name="main_banner_websocket_text">Η μετάβαση σε WebSockets είναι ο συνιστώμενος τρόπος σύνδεσης με τον διακομιστή σας και μπορεί να βελτιώσει τη διάρκεια ζωής της μπαταρίας, αλλά μπορεί να απαιτεί <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">πρόσθετες ρυθμίσεις στο διακομιστή μεσολάβησης</a>. Αυτό μπορεί να ενεργοποιηθεί στις Ρυθμίσεις.</string>
|
||||
<string name="add_dialog_login_password_hint">Κωδικός πρόσβασης</string>
|
||||
<string name="add_dialog_login_error_not_authorized">Η σύνδεση απέτυχε. Ο χρήστης %1$s δεν είναι εξουσιοδοτημένος.</string>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="channel_notifications_min_name">Min prioritato</string>
|
||||
<string name="channel_notifications_low_name">Malalta prioritato</string>
|
||||
<string name="channel_notifications_default_name">Defaŭlta prioritato</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="add_dialog_base_urls_dropdown_clear">Borrar la URL del servicio</string>
|
||||
<string name="main_banner_websocket_text">Cambiar a WebSockets es la forma recomendada para conectarse a su servidor, y podría mejorar la vida de la batería, pero puede requerir <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configuración adicional en su proxy</a>. Esto se puede cambiar en la Configuración.</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Habilitar ahora</string>
|
||||
<string name="main_menu_donate_title">Donar 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Las aplicaciones ya no se pueden instalar desde ntfy. Descárguelas a través del navegador. Consulte el issue #531 para obtener más información.</string>
|
||||
<string name="channel_notifications_group_default_name">Predeterminado</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Mantener alertas para la máxima prioridad</string>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
<string name="main_menu_report_bug_title">Teata vigadest</string>
|
||||
<string name="main_menu_docs_title">Loe dokumentatsiooni</string>
|
||||
<string name="main_menu_rate_title">Hinda rakendust ⭐</string>
|
||||
<string name="main_menu_donate_title">Toeta arendajat 💸</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Kustuta jäädavalt</string>
|
||||
<string name="main_item_status_text_not_one">%1$d teavitust</string>
|
||||
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
|
||||
|
|
@ -274,4 +273,70 @@
|
|||
<string name="settings_backup_restore_restore_successful">Taastamine õnnestus</string>
|
||||
<string name="settings_backup_restore_restore_failed">Taastamine ei õnnestunud: %1$s</string>
|
||||
<string name="settings_advanced_header">Täiendavad seadistused</string>
|
||||
<string name="settings_advanced_broadcast_title">Leviedasta sõnumeid</string>
|
||||
<string name="settings_advanced_broadcast_summary_enabled">Rakendused saavad teavitusi leviedastusena (kõik saavad sama sõnumi)</string>
|
||||
<string name="settings_advanced_broadcast_summary_disabled">Rakendused ei saa teavitusi leviedastusena</string>
|
||||
<string name="settings_advanced_unifiedpush_title">Kasuta UnifiedPushi</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy toimib UnifiedPushi levitajana</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy ei toimi UnifiedPushi levitajana</string>
|
||||
<string name="settings_advanced_record_logs_title">Salvesta logisid</string>
|
||||
<string name="settings_advanced_record_logs_summary_enabled">Login (kuni 1,000 kirjet) seadmesse…</string>
|
||||
<string name="settings_advanced_record_logs_summary_disabled">Lülita logimine sisse ja sa saad neid vigade otsimisel jagada.</string>
|
||||
<string name="settings_advanced_export_logs_title">Kopeeri logid või laadi nad üles</string>
|
||||
<string name="settings_advanced_export_logs_summary">Kopeeri logid lõikelaule või laadi nad nopaste.net teenusesse (mille omanik on ntfy autor). Seadmete nimed ja aadressid on võimalik välja jätta, kui teavituste sisusid mitte.</string>
|
||||
<string name="settings_advanced_export_logs_entry_copy_original">Kopeeri lõikelauale</string>
|
||||
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopeeri lõikelauale (tsenseerituna)</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_original">Laadi üles ja kopeeri link</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Laadi üles ja kopeeri link (tsenseerituna)</string>
|
||||
<string name="settings_advanced_export_logs_copied_logs">Logid on kopeeritud lõikelauale</string>
|
||||
<string name="settings_advanced_export_logs_uploading">Logid on üleslaadimisel…</string>
|
||||
<string name="settings_advanced_export_logs_copied_url">Logid on laaditud üles ja võrguaadress on kopeeritud</string>
|
||||
<string name="settings_advanced_export_logs_error_uploading">Logide üleslaadimine ei õnnestunud: %1$s</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_text">Need teemad ja seadmete nimed on asendatud puuviljade nimedega ja seega saad ohutumalt logi jagada:\n\n%1$s\n\nKa salasõnad on korjatud välja, kuid neid pole siin näidatud.</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_empty">Ühtegi teemat ega seadme nime polnud asendatud. Kas sul üldse on teemade tellimusi?</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Sobib</string>
|
||||
<string name="settings_advanced_clear_logs_title">Kustuta logid</string>
|
||||
<string name="settings_advanced_clear_logs_summary">Kustuta varasemad logid ja alusta nullist</string>
|
||||
<string name="settings_advanced_clear_logs_deleted_toast">Logid on kustutatud</string>
|
||||
<string name="settings_advanced_connection_protocol_title">Ühendusprotokoll</string>
|
||||
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Ühenduseks serveriga kasuta JSON-i voogedastust üle HTTP. See meetod on korralikult testitud, aga võib suurendada akukasutust.</string>
|
||||
<string name="settings_advanced_connection_protocol_summary_ws">Ühenduseks serveriga kasuta WebSocketsi protokolli. Selle meetodi kasutamine on esimene soovitus, aga see võib eeldada sinu proksiserveri täiendavat seadistamist.</string>
|
||||
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON-i voogedastus üle HTTP</string>
|
||||
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
|
||||
<string name="detail_settings_global_setting_title">Kasuta üldist seadistust</string>
|
||||
<string name="detail_settings_global_setting_suffix">kasutan üldist seadistust</string>
|
||||
<string name="detail_settings_about_header">Rakenduse teave</string>
|
||||
<string name="user_dialog_title_add">Lisa kasutaja</string>
|
||||
<string name="user_dialog_title_edit">Muuda kasutajat</string>
|
||||
<string name="user_dialog_description_edit">Sa võid muuta valitud kasutaja kasutajanime või salasõna, aga ta ka sootuks kustutada.</string>
|
||||
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
|
||||
<string name="settings_about_version_copied_to_clipboard_message">Kopeeritud lõikelauale</string>
|
||||
<string name="user_dialog_base_url_hint">Teenuse võrguaadress</string>
|
||||
<string name="user_dialog_username_hint">Kasutajanimi</string>
|
||||
<string name="user_dialog_password_hint_add">Salasõna</string>
|
||||
<string name="user_dialog_password_hint_edit">Salasõna (kui jääb tühjaks, siis ei muutu)</string>
|
||||
<string name="user_dialog_button_add">Lisa kasutaja</string>
|
||||
<string name="user_dialog_button_cancel">Katkesta</string>
|
||||
<string name="user_dialog_button_delete">Kustuta kasutaja</string>
|
||||
<string name="user_dialog_button_save">Salvesta</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Täpsed äratused</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy võib ajastada täpseid äratusi. Need on vajalikud WebSocketsi toimimiseks taustal. Klõpsa selle õiguse keelamiseks.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy ei või ajastada täpseid äratusi. Need on vajalikud WebSocketsi toimimiseks taustal. Klõpsa selle õiguse lubamiseks.</string>
|
||||
<string name="settings_about_header">Rakenduse teave</string>
|
||||
<string name="settings_about_version_title">Versioon</string>
|
||||
<string name="detail_settings_appearance_icon_error_saving">Ikooni salvestamine ei õnnestu: %1$s</string>
|
||||
<string name="detail_settings_appearance_display_name_title">Kuvatav nimi</string>
|
||||
<string name="detail_settings_appearance_display_name_message">Määra selle tellimuse jaoks eraldi kuvatav nimi. Vaikimisi nime jaoks jäta tühjaks (%1$s).</string>
|
||||
<string name="detail_settings_appearance_display_name_default_summary">%1$s (vaikimisi)</string>
|
||||
<string name="detail_settings_appearance_header">Välimus</string>
|
||||
<string name="detail_settings_appearance_icon_set_title">Tellimuse ikoon</string>
|
||||
<string name="detail_settings_appearance_icon_set_summary">Vali teavitustes kuvatav ikoon</string>
|
||||
<string name="detail_settings_appearance_icon_remove_title">Tellimuste ikoon (eemaldamiseks klõpsa)</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_title">Teavituste kohanadatud seadistused</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_on">Kasutan selle tellimuse jaoks kohandatud teavitusi</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_off">Kasutan vaikimisi teavitusi (helimärguanded, „Ära sega“ olekuga mittearvestamine, jne)</string>
|
||||
<string name="detail_settings_notifications_open_channels_title">Kohenda teavituste seadistusi</string>
|
||||
<string name="detail_settings_notifications_open_channels_summary">Helimärguanded, „Ära sega“ olekuga mittearvestamine, jne.</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Jätka pidevate märguannetega</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Anna märku vaid üks kord</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
<string name="main_menu_report_bug_title">گزارش یک نقص فنی</string>
|
||||
<string name="main_menu_docs_title">مطالعه مستندات</string>
|
||||
<string name="main_menu_rate_title">رتبه دهی به اپ ⭐</string>
|
||||
<string name="main_menu_donate_title">حمایت مالی 💸</string>
|
||||
<string name="main_item_status_text_one">%1$d اطلاعیه</string>
|
||||
<string name="main_item_status_text_not_one">%1$d اطلاعیه</string>
|
||||
<string name="main_item_status_reconnecting">در حال اتصال دوباره …</string>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
<string name="channel_subscriber_notification_noinstant_text_two">Tilattu kahteen topikkiin</string>
|
||||
<string name="detail_settings_title">Tilausasetukset</string>
|
||||
<string name="detail_item_saved_successfully">Tallennettu nimellä %1$s lataukset kansioon</string>
|
||||
<string name="settings_notifications_auto_delete_one_month">jälkeen kolmenkymmenen päivän</string>
|
||||
<string name="settings_notifications_auto_delete_one_month">Kuukauden jälkeen</string>
|
||||
<string name="channel_notifications_group_default_name">Oletus</string>
|
||||
<string name="detail_menu_test">Lähetä testi ilmoitus</string>
|
||||
<string name="settings_notifications_priority_high">korkea</string>
|
||||
|
|
@ -91,14 +91,14 @@
|
|||
<string name="channel_subscriber_service_name">Tilaus palvelu</string>
|
||||
<string name="channel_subscriber_notification_instant_text_five">Tilattu viiteen välittömään topikkiin</string>
|
||||
<string name="settings_general_users_prefs_user_add">Lisää käyttäjiä</string>
|
||||
<string name="settings_notifications_auto_delete_three_months">jälkeen kolmen kuukauden</string>
|
||||
<string name="settings_notifications_auto_delete_three_months">Kolmen kuukauden jälkeen</string>
|
||||
<string name="main_add_button_description">Lisää tilaus</string>
|
||||
<string name="notification_dialog_muted_forever_toast_message">Ilmoitukset hiljennetty</string>
|
||||
<string name="settings_notifications_muted_until_show_all">Näytä kaikki ilmoitukset</string>
|
||||
<string name="notification_popup_file_download_failed">%1$s
|
||||
\ntiedosto: %2$s, lataus virhe</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Poista pysyvästi</string>
|
||||
<string name="settings_notifications_auto_delete_three_days">Jälkeen kolmen päivän</string>
|
||||
<string name="settings_notifications_auto_delete_three_days">Kolmen päivän jälkeen</string>
|
||||
<string name="settings_general_dark_mode_summary_light">Vaalea tila päälle</string>
|
||||
<string name="detail_item_cannot_open">Ei voida avata liitettä %1$s</string>
|
||||
<string name="settings_notifications_auto_download_5m">Jos tiedoston koko on alle 5 MB</string>
|
||||
|
|
@ -147,7 +147,7 @@
|
|||
<string name="settings_backup_restore_backup_entry_everything">Kaikki</string>
|
||||
<string name="settings_general_users_summary">Lisää/poista käyttäjiä suojatuille topikeille</string>
|
||||
<string name="add_dialog_use_another_server_description">Syötä palvelun URL-osoitte alle tilataksesi topikkeja muilta palvelimilta.</string>
|
||||
<string name="settings_notifications_auto_delete_one_day">Jälkeen yhden päivän</string>
|
||||
<string name="settings_notifications_auto_delete_one_day">Päivän jälkeen</string>
|
||||
<string name="settings_general_dark_mode_summary_dark">Tumma tila päällä. Oletko vampyyri \?</string>
|
||||
<string name="settings_general_users_prefs_user_add_summary">Lisää uusi käyttäjä uudelle palvelimelle</string>
|
||||
<string name="settings_general_dark_mode_entry_system">Käytä oletusasetusta</string>
|
||||
|
|
@ -291,7 +291,7 @@
|
|||
<string name="notification_popup_file">%1$s
|
||||
\nTiedosto: %2$s</string>
|
||||
<string name="settings_notifications_muted_until_forever">Ilmoitukset mykistetty, kunnes niitä jatketaan</string>
|
||||
<string name="detail_how_to_example">Esimerkki (käytä curl):<br></br><tt>$ curl -d \"Hei\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Esimerkki (käytä curl):<br/><tt>$ curl -d "Hei" %1$s</tt> ]]></string>
|
||||
<string name="detail_settings_appearance_icon_set_title">Kuvake</string>
|
||||
<string name="detail_instant_delivery_disabled">Välitön lähetys pois</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">Tilattu neljään välittömään topikkiin</string>
|
||||
|
|
@ -314,7 +314,7 @@
|
|||
<string name="settings_notifications_auto_download_summary_always">Lataa automaattisesti liitteet</string>
|
||||
<string name="user_dialog_title_edit">Muokkaa käyttäjää</string>
|
||||
<string name="settings_backup_restore_restore_successful">Palautus onnistui</string>
|
||||
<string name="settings_notifications_auto_delete_one_week">jälkeen seitsemän päivän</string>
|
||||
<string name="settings_notifications_auto_delete_one_week">Viikon jälkeen</string>
|
||||
<string name="settings_backup_restore_restore_failed">Palautus epäonnistui: %1$s</string>
|
||||
<string name="settings_notifications_header">Ilmoitukset</string>
|
||||
<string name="detail_test_message">Tämä on testi-ilmoitus ntfy Android -sovelluksesta. Sillä on prioriteettitaso %1$d. Jos lähetät toisen, se voi näyttää erilaiselta.</string>
|
||||
|
|
@ -328,8 +328,7 @@
|
|||
<string name="settings_advanced_record_logs_title">Nauhoitetut logit</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Pidä hälytykset korkeimmalla tasolla</string>
|
||||
<string name="settings_notifications_min_priority_max">Vain maksimi ja ylittävät</string>
|
||||
<string name="settings_about_header">About</string>
|
||||
<string name="main_menu_donate_title">Lahjoita 💸</string>
|
||||
<string name="settings_about_header">Tietoja</string>
|
||||
<string name="notification_dialog_8h">8 tuntia</string>
|
||||
<string name="detail_deep_link_subscribed_toast_message">Topikki %1$s tilattu</string>
|
||||
<string name="user_dialog_username_hint">Käyttäjätunnus</string>
|
||||
|
|
@ -340,4 +339,7 @@
|
|||
<string name="main_item_status_unified_push">%1$s (Yleis Push)</string>
|
||||
<string name="detail_item_tags">Tagit %1$s</string>
|
||||
<string name="main_item_status_text_one">%1$d Huomautus</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Kysy myöhemmin</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Sulje</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Salli nyt</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -329,7 +329,6 @@
|
|||
<string name="detail_settings_about_topic_url_title">URL du sujet</string>
|
||||
<string name="channel_notifications_group_default_name">Défaut</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Conserver les notifications</string>
|
||||
<string name="main_menu_donate_title">Faire un don 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Les applications ne peuvent plus être installées. Veuillez les télécharger via un navigateur. Voir le ticket #531 pour plus de détails.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Conserver les notifications avec une priorité maximale</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_title">Paramètres personnalisés de la notification</string>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
<string name="main_menu_report_bug_title">Informar dun fallo</string>
|
||||
<string name="main_menu_docs_title">Ler documentación</string>
|
||||
<string name="main_menu_rate_title">Valorar a app ⭐</string>
|
||||
<string name="main_menu_donate_title">Doar 💸</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">Retirar subscrición</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Retirar a subscrición ao(s) asunto(s) seleccionado(s) e eliminar definitivamente tódalas notificacións\?</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Eliminar definitivamente</string>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@
|
|||
<string name="add_dialog_title">विषय की सदस्यता लें</string>
|
||||
<string name="add_dialog_button_back">पीछे जाएं</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_one">एक विषय की सदस्यता</string>
|
||||
<string name="main_menu_donate_title">दान करें</string>
|
||||
<string name="main_item_status_text_one">%1$d सूचना</string>
|
||||
<string name="detail_clear_dialog_cancel">रद्द करें</string>
|
||||
<string name="detail_delete_dialog_cancel">रद्द करें</string>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@
|
|||
<string name="main_item_status_reconnecting">ponovno povezivanje…</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Uključi sada</string>
|
||||
<string name="main_banner_websocket_text">Prebacivanje na WebSockete je preporučen način povezivanja sa serverom, i moglo bi poboljšati životni vijek baterije, ali može zahtjevati <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">dodatnu konfiguraciju u tvojem proxy-u</a>. Ovo možeš promijeniti u postavkama.</string>
|
||||
<string name="main_menu_donate_title">Doniraj 💸</string>
|
||||
<string name="main_menu_report_bug_title">Prijavu grešku</string>
|
||||
<string name="main_how_to_link">Opširnije upute dostupne su na ntfy.sh i u dokumentaciji.</string>
|
||||
<string name="main_how_to_intro">Klikni + za kreiranje ili pretplaćivanje na temu. Nakon toga primaš obavijesti na uređaj kad pošalješ poruke preko PUT ili POST.</string>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
<string name="main_item_status_text_one">%1$d értesítés</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Mégse</string>
|
||||
<string name="channel_notifications_group_default_name">Alapértelmezett</string>
|
||||
<string name="main_menu_donate_title">Adomány 💸</string>
|
||||
<string name="main_banner_websocket_button_dismiss">Bezár</string>
|
||||
<string name="add_dialog_instant_delivery_description">Garantálja az azonnali üzenetküldést, akkor is, ha az eszköz inaktív.</string>
|
||||
<string name="add_dialog_foreground_description">Az azonnali üzenetküldés mindig bekapcsolva a %1$s címen kívül.</string>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<string name="add_dialog_login_new_user">Pengguna baru</string>
|
||||
<string name="detail_no_notifications_text">Anda belum menerima notifikasi apa pun.</string>
|
||||
<string name="detail_how_to_intro">Untuk mengirimkan notifikasi ke topik ini, lakukan PUT atau POST ke URL topik.</string>
|
||||
<string name="detail_how_to_example">Contoh (menggunakan curl):<br></br><tt>$ curl -d \"Hai\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Contoh (menggunakan curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string>
|
||||
<string name="detail_how_to_link">Instruksi rinci tersedia di ntfy.sh, dan dalam dokumentasi.</string>
|
||||
<string name="detail_clear_dialog_message">Hapus semua notifikasi di topik ini\?</string>
|
||||
<string name="detail_clear_dialog_permanently_delete">Hapus secara permanen</string>
|
||||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Disalin ke papan klip</string>
|
||||
<string name="detail_settings_about_header">Tentang</string>
|
||||
<string name="detail_settings_about_topic_url_title">URL Topik</string>
|
||||
<string name="main_menu_donate_title">Donasi 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Aplikasi tidak dapat dipasang lagi. Unduh melalui peramban. Lihat masalah #531 untuk detail lebih lanjut.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">Notifikasi prioritas maks hanya memperingati sekali</string>
|
||||
<string name="detail_settings_notifications_open_channels_title">Atur pengaturan notifikasi</string>
|
||||
|
|
@ -343,4 +342,11 @@
|
|||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy akan menjadi sebagai distributor UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy tidak akan menjadi sebagai distributor UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_title">Aktifkan UnifiedPush</string>
|
||||
<string name="main_banner_websocket_reconnect_text">Untuk memastikan WebSockets tersambung kembali di latar belakang, berikan izin Alarm & Pengingat untuk ntfy</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Tanyakan nanti</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Singkirkan</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Berikan sekarang</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Alarm akurat</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy dapat menjadwalkan alarm yang tepat. Alarm yang tepat diperlukan untuk menyambungkan kembali WebSockets di latar belakang. Klik untuk mencabut izin.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy tidak dapat menjadwalkan alarm yang tepat. Alarm yang tepat diperlukan untuk menyambungkan kembali WebSockets di latar belakang. Klik untuk memberikan izin.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="channel_notifications_low_name">Priorità bassa</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_three">Iscritto a tre topic</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_three">Iscritto a tre argomenti</string>
|
||||
<string name="channel_notifications_high_name">Priorità alta</string>
|
||||
<string name="channel_notifications_max_name">Priorità massima</string>
|
||||
<string name="channel_subscriber_service_name">Servizio di iscrizione</string>
|
||||
<string name="channel_subscriber_notification_instant_text">Iscritto ai topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_two">Iscritto a due topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_three">Iscritto a tre topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">Iscritto a quattro topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_more">Iscritto a %1$d topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text">Iscritto ai topic</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_one">Iscritto a un topic</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_two">Iscritto a due topic</string>
|
||||
<string name="channel_subscriber_notification_instant_text">Iscritto ad argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_two">Iscritto a due argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_three">Iscritto a tre argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">Iscritto a quattro argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_more">Iscritto a %1$d argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text">Iscritto agli argomenti</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_one">Iscritto ad un argomento</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_two">Iscritto a due argomenti</string>
|
||||
<string name="refresh_message_result">%1$d notifiche ricevute</string>
|
||||
<string name="refresh_message_no_results">Tutto è aggiornato</string>
|
||||
<string name="refresh_message_error">Impossibile aggiornare %1$d iscrizioni
|
||||
|
|
@ -23,73 +23,73 @@
|
|||
<string name="main_menu_notifications_disabled_forever">Notifiche disattivate</string>
|
||||
<string name="main_menu_notifications_disabled_until">Notiche disattivate fino a %1$s</string>
|
||||
<string name="main_menu_settings_title">Impostazioni</string>
|
||||
<string name="main_action_bar_title">Topic iscritti</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Disiscriversi dai topic selezionati ed eliminare definitivamente tutte le notifiche\?</string>
|
||||
<string name="main_action_bar_title">Argomenti sottoscritti</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Disiscriversi dagli argomenti selezionati ed eliminare definitivamente tutte le notifiche?</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Elimina definitivamente</string>
|
||||
<string name="main_item_status_text_one">%1$d notifiche</string>
|
||||
<string name="main_item_status_text_not_one">%1$d notifiche</string>
|
||||
<string name="main_item_status_reconnecting">riconnessione…</string>
|
||||
<string name="main_item_date_yesterday">ieri</string>
|
||||
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
|
||||
<string name="main_how_to_link">Istruzioni dettagliate disponibili su ntfy.sh, e nella documentazione.</string>
|
||||
<string name="main_how_to_link">Istruzioni dettagliate disponibili su ntfy.sh e nella documentazione.</string>
|
||||
<string name="main_unified_push_toast">Questa iscrizione è gestita da %1$s via UnifiedPush</string>
|
||||
<string name="main_banner_battery_button_remind_later">Chiedi in seguito</string>
|
||||
<string name="main_banner_battery_button_dismiss">Abbandona</string>
|
||||
<string name="main_banner_battery_button_fix_now">Correggi ora</string>
|
||||
<string name="main_banner_websocket_button_remind_later">Chiedi in seguito</string>
|
||||
<string name="main_banner_websocket_button_dismiss">Abbandona</string>
|
||||
<string name="add_dialog_title">Iscriviti al topic</string>
|
||||
<string name="add_dialog_topic_name_hint">Nome del topic, es. phils_alerts</string>
|
||||
<string name="add_dialog_title">Iscriviti all\'argomento</string>
|
||||
<string name="add_dialog_topic_name_hint">Nome dell\'argomento, es. phils_alerts</string>
|
||||
<string name="add_dialog_use_another_server">Usa un altro server</string>
|
||||
<string name="add_dialog_use_another_server_description">Immettere gli URL dei servizi qui sotto per iscriversi ai topic di altri server.</string>
|
||||
<string name="add_dialog_use_another_server_description">Inserisci gli URL dei servizi qui sotto per iscriversi agli argomenti di altri server.</string>
|
||||
<string name="add_dialog_instant_delivery">Consegna istantanea in modalità doze</string>
|
||||
<string name="add_dialog_foreground_description">La consegna istantanea è sempre attiva per gli host diversi da %1$s.</string>
|
||||
<string name="add_dialog_button_cancel">Cancella</string>
|
||||
<string name="add_dialog_button_login">Log in</string>
|
||||
<string name="add_dialog_foreground_description">La consegna istantanea è sempre attiva per i sistemi diversi da %1$s.</string>
|
||||
<string name="add_dialog_button_cancel">Annulla</string>
|
||||
<string name="add_dialog_button_login">Accesso</string>
|
||||
<string name="add_dialog_error_connection_failed">Connessione fallita: %1$s</string>
|
||||
<string name="add_dialog_login_title">Login richiesto</string>
|
||||
<string name="add_dialog_login_username_hint">Username</string>
|
||||
<string name="add_dialog_login_title">Accesso richiesto</string>
|
||||
<string name="add_dialog_login_username_hint">Nome utente</string>
|
||||
<string name="add_dialog_login_password_hint">Password</string>
|
||||
<string name="add_dialog_login_error_not_authorized">Login fallito. Utente %1$s non autorizzato.</string>
|
||||
<string name="add_dialog_login_error_not_authorized">Accesso fallito. Utente %1$s non autorizzato.</string>
|
||||
<string name="add_dialog_login_new_user">Nuovo utente</string>
|
||||
<string name="detail_how_to_intro">Per inviare notifiche a questo topic, usa PUT o POST all\'URL del topic.</string>
|
||||
<string name="detail_how_to_link">Istruzioni dettagliate disponibili su ntfy.sh, e nella documentazione.</string>
|
||||
<string name="detail_clear_dialog_message">Eliminare tutte le notifiche in questo topic\?</string>
|
||||
<string name="detail_how_to_intro">Per inviare notifiche a questo argomento, usa PUT o POST all\'URL dell\'argomento.</string>
|
||||
<string name="detail_how_to_link">Istruzioni dettagliate disponibili su ntfy.sh e nella documentazione.</string>
|
||||
<string name="detail_clear_dialog_message">Eliminare tutte le notifiche in questo argomento?</string>
|
||||
<string name="detail_clear_dialog_permanently_delete">Elimina definitivamente</string>
|
||||
<string name="detail_clear_dialog_cancel">Cancella</string>
|
||||
<string name="detail_delete_dialog_message">Disiscriversi da questo topic e cancellare tutte le notifiche ricevute\?</string>
|
||||
<string name="detail_clear_dialog_cancel">Annulla</string>
|
||||
<string name="detail_delete_dialog_message">Disiscriversi da questo argomento ed eliminare tutte le notifiche ricevute?</string>
|
||||
<string name="detail_delete_dialog_permanently_delete">Elimina definitivamente</string>
|
||||
<string name="detail_delete_dialog_cancel">Cancella</string>
|
||||
<string name="detail_delete_dialog_cancel">Annulla</string>
|
||||
<string name="detail_test_title">Test: Puoi impostare un titolo, se vuoi.</string>
|
||||
<string name="detail_test_message_error_unauthorized_anon">Impossibile inviare il messaggio: Pubblicazione anonima non permessa.</string>
|
||||
<string name="detail_test_message_error_unauthorized_user">Impossibile inviare il messaggio: L\'utente \"%1$s\" non è autorizzato.</string>
|
||||
<string name="detail_copied_to_clipboard_message">Copiato negli appunti</string>
|
||||
<string name="detail_instant_delivery_enabled">Consegna istantanea ON</string>
|
||||
<string name="detail_item_tags">Tags: %1$s</string>
|
||||
<string name="detail_instant_delivery_enabled">Consegna istantanea ATTIVATA</string>
|
||||
<string name="detail_item_tags">Etichette: %1$s</string>
|
||||
<string name="detail_test_message_error_too_large">Impossibile inviare il messaggio: L\'allegato è troppo grande.</string>
|
||||
<string name="detail_item_snack_deleted">Notifica eliminata</string>
|
||||
<string name="detail_item_snack_undo">Annulla</string>
|
||||
<string name="detail_item_menu_copy_contents_copied">Notifica copiata negli appunti</string>
|
||||
<string name="detail_item_cannot_download">Impossibile aprire o scaricare l\'allegato. Il link è scaduto e nessun file locale è stato trovato.</string>
|
||||
<string name="detail_item_cannot_download">Impossibile aprire o scaricare l\'allegato. Il collegamento è scaduto e nessun file locale è stato trovato.</string>
|
||||
<string name="detail_item_cannot_open">Impossibile aprire l\'allegato: %1$s</string>
|
||||
<string name="detail_item_cannot_open_url">Impossibile aprire URL: %1$s</string>
|
||||
<string name="detail_item_cannot_delete">Impossibile eliminare l\'allegato: %1$s</string>
|
||||
<string name="detail_item_download_failed">Impossibile scaricare l\'allegato: %1$s</string>
|
||||
<string name="detail_item_download_info_not_downloaded">non scaricato</string>
|
||||
<string name="detail_item_download_info_not_downloaded_expired">non scaricato, link scaduto</string>
|
||||
<string name="detail_item_download_info_not_downloaded_expired">non scaricato, collegamento scaduto</string>
|
||||
<string name="detail_item_download_info_not_downloaded_expires_x">non scaricato, scadenza %1$s</string>
|
||||
<string name="detail_item_download_info_downloading_x_percent">%1$d%% scaricato</string>
|
||||
<string name="detail_item_download_info_deleted">eliminato</string>
|
||||
<string name="detail_item_download_info_deleted_expired">eliminato, link scaduto</string>
|
||||
<string name="detail_item_download_info_deleted_expires_x">eliminato, scadenza link %1$s</string>
|
||||
<string name="detail_item_download_info_deleted_expired">eliminato, collegamento scaduto</string>
|
||||
<string name="detail_item_download_info_deleted_expires_x">eliminato, scadenza collegamento %1$s</string>
|
||||
<string name="detail_item_download_info_download_failed">download fallito</string>
|
||||
<string name="detail_item_download_info_download_failed_expired">download fallito, link scaduto</string>
|
||||
<string name="detail_item_download_info_download_failed_expired">download fallito, collegamento scaduto</string>
|
||||
<string name="detail_menu_notifications_disabled_forever">Notifiche disattivate</string>
|
||||
<string name="detail_menu_notifications_disabled_until">Notifiche disattivate fino a %1$s</string>
|
||||
<string name="detail_menu_enable_instant">Abilita consegna istantanea</string>
|
||||
<string name="detail_menu_disable_instant">Disabilita consegna istantanea</string>
|
||||
<string name="detail_menu_test">Invia notifica di test</string>
|
||||
<string name="detail_item_download_info_download_failed_expires_x">download fallito, scadenza link %1$s</string>
|
||||
<string name="detail_item_download_info_download_failed_expires_x">download fallito, scadenza collegamento %1$s</string>
|
||||
<string name="detail_menu_clear">Cancella tutte le notifiche</string>
|
||||
<string name="detail_action_mode_menu_delete">Elimina</string>
|
||||
<string name="detail_action_mode_delete_dialog_message">Eliminare definitivamente le notifiche selezionate\?</string>
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
<string name="share_content_image_error">Impossibile leggere l\'immagine: %1$s</string>
|
||||
<string name="share_topic_title">Condividi con</string>
|
||||
<string name="share_successful">Messaggio pubblicato</string>
|
||||
<string name="notification_dialog_cancel">Cancella</string>
|
||||
<string name="notification_dialog_cancel">Annulla</string>
|
||||
<string name="notification_dialog_show_all">Mostra tutte le notifiche</string>
|
||||
<string name="notification_dialog_1h">1 ora</string>
|
||||
<string name="notification_dialog_tomorrow">Fino a domani</string>
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
<string name="settings_notifications_min_priority_summary_max">Mostra notifiche se la priorità è 5 (max)</string>
|
||||
<string name="settings_notifications_min_priority_min">Tutte le priorità</string>
|
||||
<string name="settings_notifications_min_priority_low">Priorità bassa e superiori</string>
|
||||
<string name="settings_notifications_min_priority_default">Priorità di default e superiori</string>
|
||||
<string name="settings_notifications_min_priority_default">Priorità predefinita e superiori</string>
|
||||
<string name="settings_notifications_min_priority_high">Priorità alta e superiori</string>
|
||||
<string name="settings_notifications_min_priority_max">Solo priorità massima</string>
|
||||
<string name="settings_notifications_auto_download_summary_always">Scarica automaticamente tutti gli allegati</string>
|
||||
|
|
@ -137,78 +137,74 @@
|
|||
<string name="settings_notifications_auto_download_100k">Se sotto 100kB</string>
|
||||
<string name="settings_notifications_auto_download_500k">Se sotto 500 kB</string>
|
||||
<string name="settings_notifications_auto_delete_title">Elimina tutte le notifiche</string>
|
||||
<string name="settings_general_default_base_url_title">Server di default</string>
|
||||
<string name="settings_general_default_base_url_title">Server predefinito</string>
|
||||
<string name="settings_general_header">Generale</string>
|
||||
<string name="settings_general_default_base_url_default_summary">%1$s (default)</string>
|
||||
<string name="settings_general_default_base_url_default_summary">%1$s (predefinito)</string>
|
||||
<string name="settings_general_users_title">Gestisci utenti</string>
|
||||
<string name="settings_general_users_summary">Aggiungi/rimuovi utenti per topic protetti</string>
|
||||
<string name="settings_general_users_summary">Aggiungi/rimuovi utenti per argomenti protetti</string>
|
||||
<string name="settings_general_users_prefs_title">Utenti</string>
|
||||
<string name="settings_general_users_prefs_user_not_used">Non utilizzato da nessun topic</string>
|
||||
<string name="settings_general_users_prefs_user_used_by_one">Utilizzato dal topic %1$s</string>
|
||||
<string name="settings_general_users_prefs_user_not_used">Non utilizzato da nessun argomento</string>
|
||||
<string name="settings_general_users_prefs_user_used_by_one">Utilizzato dall\'argomento %1$s</string>
|
||||
<string name="settings_general_users_prefs_user_add_title">Aggiungi nuovo utente</string>
|
||||
<string name="settings_general_users_prefs_user_add_summary">Crea un nuovo utente per un nuovo server</string>
|
||||
<string name="settings_general_dark_mode_title">Modalità dark</string>
|
||||
<string name="settings_general_dark_mode_summary_system">Utilizzando il default di sistema</string>
|
||||
<string name="settings_general_dark_mode_summary_light">Modalità light ON</string>
|
||||
<string name="settings_general_dark_mode_entry_system">Usa il default di sistema</string>
|
||||
<string name="settings_general_dark_mode_entry_light">Modalità light</string>
|
||||
<string name="settings_general_dark_mode_title">Modalità scura</string>
|
||||
<string name="settings_general_dark_mode_summary_system">Utilizzo impostazione predefinita di sistema</string>
|
||||
<string name="settings_general_dark_mode_summary_light">Modalità chiara attiva</string>
|
||||
<string name="settings_general_dark_mode_entry_system">Usa impostazione predefinita di sistema</string>
|
||||
<string name="settings_general_dark_mode_entry_light">Modalità chiara</string>
|
||||
<string name="settings_backup_restore_backup_entry_settings_only">Solo le impostazioni</string>
|
||||
<string name="settings_advanced_broadcast_title">Messaggi broadcast</string>
|
||||
<string name="settings_advanced_broadcast_summary_enabled">Le app possono ricevere le notifiche in ingresso come broadcast</string>
|
||||
<string name="settings_advanced_record_logs_title">Abilita registrazione dei log</string>
|
||||
<string name="settings_advanced_export_logs_copied_url">Log caricati e URL copiato</string>
|
||||
<string name="settings_advanced_export_logs_error_uploading">Impossibile caricare i log: %1$s</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_empty">Nessun topic/hostname è stato redatto. Forse non hai iscrizioni\?</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_text">Questi topic/hostnames sono stati sostituiti con nomi di frutta, così puoi condividere i log senza preoccupazioni:
|
||||
\n
|
||||
\n%1$s
|
||||
\n
|
||||
\nLe password sono state ripulite, ma non sono elencate qui.</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_empty">Nessun argomento/nome di sistema è stato redatto. Forse non hai iscrizioni?</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_text">Questi argomenti/nomi di sistema sono stati sostituiti con nomi di frutta, così puoi condividere i log senza preoccupazioni: \n \n%1$s \n \nLe password sono state ripulite, ma non sono elencate qui.</string>
|
||||
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Ok</string>
|
||||
<string name="settings_advanced_clear_logs_title">Cancella i log</string>
|
||||
<string name="settings_advanced_clear_logs_title">Cancella i registri</string>
|
||||
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usa stream JSON over HTTP per collegarti al server. Questo metodo è collaudato, ma può consumare più batteria.</string>
|
||||
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Stream JSON over HTTP</string>
|
||||
<string name="user_dialog_description_add">Puoi aggiungere un utente qui. Tutti i topic per il dato server utilizzeranno questo utente.</string>
|
||||
<string name="user_dialog_description_edit">Puoi modificare username/password per l\'utente selezionato, oppure eliminarlo.</string>
|
||||
<string name="user_dialog_description_add">Puoi aggiungere un utente qui. Tutti gli argomenti per il server specificato utilizzeranno questo utente.</string>
|
||||
<string name="user_dialog_description_edit">Puoi modificare nome utente/password per l\'utente selezionato, oppure eliminarlo.</string>
|
||||
<string name="user_dialog_base_url_hint">URL del servizio</string>
|
||||
<string name="user_dialog_username_hint">Username</string>
|
||||
<string name="user_dialog_username_hint">Nome utente</string>
|
||||
<string name="user_dialog_password_hint_add">Password</string>
|
||||
<string name="user_dialog_password_hint_edit">Password (non modificata se il campo viene lasciato vuoto)</string>
|
||||
<string name="user_dialog_button_add">Aggiungi utente</string>
|
||||
<string name="user_dialog_button_cancel">Cancella</string>
|
||||
<string name="user_dialog_button_cancel">Annulla</string>
|
||||
<string name="user_dialog_button_delete">Elimina utente</string>
|
||||
<string name="user_dialog_button_save">Salva</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_more">Iscritto a %1$d topic</string>
|
||||
<string name="channel_notifications_default_name">Priorità di default</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_more">Iscritto a %1$d argomenti</string>
|
||||
<string name="channel_notifications_default_name">Priorità predefinita</string>
|
||||
<string name="channel_notifications_min_name">Priorità minima</string>
|
||||
<string name="channel_subscriber_notification_instant_text_one">Iscritto a un topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_four">Iscritto a quattro topic</string>
|
||||
<string name="channel_subscriber_notification_instant_text_one">Iscritto ad un argomento a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_four">Iscritto a quattro argomenti</string>
|
||||
<string name="main_menu_docs_title">Leggi la documentazione</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">Disiscriviti</string>
|
||||
<string name="main_how_to_intro">Clicca + per creare o iscriversi ad un topic. In seguito, riceverai notifiche sul tuo device quando invierai messaggi via PUT o POST.</string>
|
||||
<string name="main_how_to_intro">Clicca + per creare o iscriversi ad un argomento. In seguito, riceverai notifiche sul tuo dispositivo quando invierai messaggi via PUT o POST.</string>
|
||||
<string name="main_banner_battery_text">L\'ottimizzazione della batteria deve essere disabilitata per l\'app per evitare problemi di consegna delle notifiche.</string>
|
||||
<string name="main_add_button_description">Aggiungi iscrizione</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Cancella</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Annulla</string>
|
||||
<string name="main_no_subscriptions_text">Sembra che non ci sia nessuna iscrizione al momento.</string>
|
||||
<string name="main_menu_report_bug_title">Segnala un bug</string>
|
||||
<string name="main_menu_report_bug_title">Segnala un problema</string>
|
||||
<string name="main_menu_rate_title">Valuta l\'app ⭐</string>
|
||||
<string name="add_dialog_description_below">I topic possono essere non protetti da password, per cui scegli un nome che è difficile da indovinare. Una volta iscritti, è possibile effettuare notifiche PUT/POST.</string>
|
||||
<string name="add_dialog_description_below">Gli argomenti possono essere non protetti da password, per cui scegli un nome che sia difficile da indovinare. Una volta iscritto, è possibile effettuare notifiche PUT/POST.</string>
|
||||
<string name="add_dialog_instant_delivery_description">Assicura che i messaggi siano consegnati immediatamente, anche se il device non è attivo.</string>
|
||||
<string name="add_dialog_login_description">Questo topic richiede il login. Per favore, inserire username e password.</string>
|
||||
<string name="add_dialog_login_description">Questo argomento richiede l\'accesso. Per favore, inserisci nome utente e password.</string>
|
||||
<string name="add_dialog_button_subscribe">Iscriviti</string>
|
||||
<string name="add_dialog_button_back">Indietro</string>
|
||||
<string name="detail_no_notifications_text">Non hai ancora ricevuto notifiche su questo topic.</string>
|
||||
<string name="detail_no_notifications_text">Non hai ancora ricevuto notifiche su questo argomento.</string>
|
||||
<string name="detail_item_menu_open">Apri file</string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Esempio (utilizzando curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string>
|
||||
<string name="detail_instant_delivery_disabled">Consegna istantanea OFF</string>
|
||||
<string name="detail_instant_delivery_disabled">Consegna istantanea DISATTIVATA</string>
|
||||
<string name="detail_item_menu_delete">Elimina file</string>
|
||||
<string name="detail_item_menu_save_file">Salva il file</string>
|
||||
<string name="detail_item_menu_copy_url">Copia URL</string>
|
||||
<string name="detail_menu_copy_url">Copia l\'indirizzo del topic</string>
|
||||
<string name="detail_menu_copy_url">Copia l\'indirizzo dell\'argomento</string>
|
||||
<string name="detail_item_menu_copy_url_copied">URL copiato negli appunti</string>
|
||||
<string name="detail_menu_notifications_enabled">Notifiche ON</string>
|
||||
<string name="detail_test_message_error">Impossibile inviare il messaggio: %1$s</string>
|
||||
<string name="detail_item_menu_cancel">Interrompi il download</string>
|
||||
<string name="detail_item_menu_cancel">Annulla download</string>
|
||||
<string name="detail_item_menu_copy_contents">Copia notifica</string>
|
||||
<string name="detail_item_saved_successfully">Salvato con nome \"%1$s\" nella cartella \"Downloads\"</string>
|
||||
<string name="detail_item_cannot_save">Impossibile salvare l\'allegato: %1$s</string>
|
||||
|
|
@ -230,21 +226,21 @@
|
|||
<string name="settings_notifications_auto_download_title">Scarica allegati</string>
|
||||
<string name="detail_item_menu_download">Scarica file</string>
|
||||
<string name="notification_popup_action_download">Scarica</string>
|
||||
<string name="notification_popup_action_cancel">Cancella</string>
|
||||
<string name="notification_popup_action_cancel">Annulla</string>
|
||||
<string name="settings_notifications_auto_download_always">Scarica tutto automaticamente</string>
|
||||
<string name="settings_notifications_auto_download_1m">Se sotto 1 MB</string>
|
||||
<string name="settings_notifications_auto_download_10m">Se sotto 10 MB</string>
|
||||
<string name="settings_notifications_auto_download_50m">Se sotto 50 MB</string>
|
||||
<string name="detail_item_cannot_open_not_found">Impossibile aprire l\'allegato: Il file può essere stato cancellato oppure nessuna app installata è in grado di aprire il file.</string>
|
||||
<string name="detail_item_cannot_open_not_found">Impossibile aprire l\'allegato: Il file può essere stato eliminato oppure nessuna app installata è in grado di aprire il file.</string>
|
||||
<string name="detail_menu_unsubscribe">Disiscriviti</string>
|
||||
<string name="detail_action_mode_delete_dialog_cancel">Cancella</string>
|
||||
<string name="detail_action_mode_delete_dialog_cancel">Annulla</string>
|
||||
<string name="settings_notifications_header">Notifiche</string>
|
||||
<string name="share_content_file_error">Impossibile leggere le informazioni del file: %1$s</string>
|
||||
<string name="notification_popup_action_open">Apri</string>
|
||||
<string name="settings_notifications_muted_until_forever">Notifiche disattivate fino al ripristino</string>
|
||||
<string name="settings_notifications_auto_download_5m">Se sotto 5 MB</string>
|
||||
<string name="share_content_file_text">Un file è stato condiviso con te</string>
|
||||
<string name="share_suggested_topics">Topic suggeriti</string>
|
||||
<string name="share_suggested_topics">Argomenti suggeriti</string>
|
||||
<string name="notification_dialog_title">Disattivare le notifiche</string>
|
||||
<string name="notification_dialog_save">Salva</string>
|
||||
<string name="notification_dialog_enabled_toast_message">Notifiche ripristinate</string>
|
||||
|
|
@ -255,34 +251,34 @@
|
|||
<string name="notification_dialog_8h">8 ore</string>
|
||||
<string name="settings_backup_restore_backup_entry_everything_no_users">Tutto, eccetto utenti</string>
|
||||
<string name="settings_advanced_header">Avanzate</string>
|
||||
<string name="settings_general_default_base_url_message">Inserisci il root URL del tuo server per utilizzarlo come default durante l\'iscrizione a nuovi topic e/o durante la condivisione ai topic.</string>
|
||||
<string name="settings_general_users_prefs_user_used_by_many">Utilizzato dai topic %1$s</string>
|
||||
<string name="settings_general_default_base_url_message">Inserisci l\'URL radice del tuo server per utilizzare il tuo server come predefinito quando ti iscrivi a nuovi argomenti e/o condividi argomenti.</string>
|
||||
<string name="settings_general_users_prefs_user_used_by_many">Utilizzato dagli argomenti %1$s</string>
|
||||
<string name="settings_general_users_prefs_user_add">Aggiungi utente</string>
|
||||
<string name="settings_general_dark_mode_entry_dark">Modalità dark</string>
|
||||
<string name="settings_general_dark_mode_entry_dark">Modalità scura</string>
|
||||
<string name="settings_backup_restore_backup_title">Backup su file</string>
|
||||
<string name="settings_general_dark_mode_summary_dark">Modalità dark ON. Sei un vampiro\?</string>
|
||||
<string name="settings_general_dark_mode_summary_dark">Modalità scura attiva. Sei un vampiro?</string>
|
||||
<string name="settings_backup_restore_header">Backup & Ripristino</string>
|
||||
<string name="settings_backup_restore_restore_failed">Ripristino fallito: %1$s</string>
|
||||
<string name="settings_advanced_export_logs_copied_logs">Log copiati negli appunti</string>
|
||||
<string name="settings_about_header">Informazioni</string>
|
||||
<string name="settings_backup_restore_backup_summary">Esporta config, notifiche e utenti</string>
|
||||
<string name="settings_backup_restore_backup_summary">Esporta configurazione, notifiche e utenti</string>
|
||||
<string name="settings_backup_restore_backup_entry_everything">Tutto</string>
|
||||
<string name="settings_backup_restore_backup_successful">Backup creato</string>
|
||||
<string name="settings_backup_restore_backup_failed">Backup fallito: %1$s</string>
|
||||
<string name="settings_backup_restore_restore_title">Ripristina da file</string>
|
||||
<string name="settings_backup_restore_restore_summary">Importa config, notifiche e utenti</string>
|
||||
<string name="settings_advanced_record_logs_summary_enabled">Logging (fino a 1,000 elementi) nel device …</string>
|
||||
<string name="settings_backup_restore_restore_summary">Importa configurazione, notifiche e utenti</string>
|
||||
<string name="settings_advanced_record_logs_summary_enabled">Registrazione (fino a 1.000 voci) sul dispositivo …</string>
|
||||
<string name="settings_backup_restore_restore_successful">Ripristino riuscito</string>
|
||||
<string name="settings_advanced_broadcast_summary_disabled">Le app non possono ricevere le notifiche come broadcast</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_original">Carica e copia link</string>
|
||||
<string name="settings_advanced_record_logs_summary_disabled">Attiva la trascrizione dei log per condividere file di log in seguito per diagnosticare problemi.</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_original">Carica e copia collegamento</string>
|
||||
<string name="settings_advanced_record_logs_summary_disabled">Attiva la registrazione, così potrai condividere i registri in un secondo momento per diagnosticare i problemi.</string>
|
||||
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Copia negli appunti (censurato)</string>
|
||||
<string name="settings_about_version_title">Versione</string>
|
||||
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
|
||||
<string name="settings_advanced_export_logs_title">Copia/upload file di log</string>
|
||||
<string name="settings_advanced_export_logs_entry_copy_original">Copia negli appunti</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Carica e copia link (censurato)</string>
|
||||
<string name="settings_advanced_export_logs_uploading">Log in upload …</string>
|
||||
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Carica e copia collegamento (censurato)</string>
|
||||
<string name="settings_advanced_export_logs_uploading">Caricando registri …</string>
|
||||
<string name="settings_advanced_clear_logs_summary">Elimina i log precedentemente salvati, e ricomincia</string>
|
||||
<string name="settings_advanced_connection_protocol_title">Protocollo di connessione</string>
|
||||
<string name="settings_advanced_connection_protocol_summary_ws">Usa WebSockets per collegarti al server. Questo è il metodo consigliato, ma potrebbe richiedere una configurazione aggiuntiva del proxy.</string>
|
||||
|
|
@ -292,19 +288,19 @@
|
|||
<string name="user_dialog_title_edit">Modifica utente</string>
|
||||
<string name="channel_subscriber_notification_title">In attesa di notifiche in ingresso</string>
|
||||
<string name="detail_test_message">Questa è una notifica test dall\'app Android ntfy. Ha livello di priorità %1$d. Se ne invii un\'altra, potrebbe avere contenuti differenti.</string>
|
||||
<string name="settings_advanced_export_logs_summary">Copia i log negli appunti, o carica su nopaste.net (in possesso dell\'autore di ntfy). Hostname e topic possono essere censurati, le notifiche non lo saranno mai.</string>
|
||||
<string name="settings_notifications_priority_default">default</string>
|
||||
<string name="settings_advanced_export_logs_summary">Copia i log negli appunti, o carica su nopaste.net (in possesso dell\'autore di ntfy). I nomi di sistema e gli argomenti possono essere censurati, le notifiche non lo saranno mai.</string>
|
||||
<string name="settings_notifications_priority_default">predefinita</string>
|
||||
<string name="settings_notifications_priority_max">massima</string>
|
||||
<string name="settings_notifications_priority_high">alta</string>
|
||||
<string name="settings_notifications_priority_min">minima</string>
|
||||
<string name="settings_notifications_priority_low">bassa</string>
|
||||
<string name="detail_deep_link_subscribed_toast_message">Iscritto al topic %1$s</string>
|
||||
<string name="detail_deep_link_subscribed_toast_message">Iscritto all\'argomento %1$s</string>
|
||||
<string name="detail_settings_global_setting_title">Utilizzare l\'impostazione globale</string>
|
||||
<string name="settings_notifications_channel_prefs_summary">Esclusione del DND (Do Not Disturb), suoni, ecc.</string>
|
||||
<string name="channel_subscriber_notification_instant_text_five">Iscritto a cinque topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_six">Iscritto a sei topic a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_five">Iscritto a cinque topic</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_six">Iscritto a sei topic</string>
|
||||
<string name="settings_notifications_channel_prefs_summary">Disattivazione funzione Non disturbare (DND), suoni, ecc.</string>
|
||||
<string name="channel_subscriber_notification_instant_text_five">Iscritto a cinque argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_instant_text_six">Iscritto a sei argomenti a consegna istantanea</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_five">Iscritto a cinque argomenti</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_six">Iscritto a sei argomenti</string>
|
||||
<string name="notification_popup_user_action_failed">%1$s fallito: %2$s</string>
|
||||
<string name="settings_notifications_channel_prefs_title">Impostazioni del canale</string>
|
||||
<string name="detail_settings_notifications_instant_title">Consegna istantanea</string>
|
||||
|
|
@ -314,7 +310,7 @@
|
|||
<string name="detail_settings_appearance_icon_set_title">Icona della sottoscrizione</string>
|
||||
<string name="detail_settings_appearance_icon_set_summary">Impostare un\'icona da visualizzare nelle notifiche</string>
|
||||
<string name="detail_settings_appearance_icon_remove_title">Icona della sottoscrizione (toccare per rimuovere)</string>
|
||||
<string name="detail_settings_appearance_icon_remove_summary">Icona visualizzata nelle notifiche di questo topic</string>
|
||||
<string name="detail_settings_appearance_icon_remove_summary">Icona visualizzata nelle notifiche di questo argomento</string>
|
||||
<string name="detail_settings_appearance_icon_error_saving">Impossibile salvare l\'icona: %1$s</string>
|
||||
<string name="detail_settings_global_setting_suffix">utilizzando l\'impostazione globale</string>
|
||||
<string name="detail_settings_appearance_display_name_title">Nome visualizzato</string>
|
||||
|
|
@ -327,18 +323,17 @@
|
|||
<string name="add_dialog_base_urls_dropdown_choose">Scegli il servizio URL</string>
|
||||
<string name="add_dialog_base_urls_dropdown_clear">Pulisci il servizio URL</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Attiva ora</string>
|
||||
<string name="channel_notifications_group_default_name">Default</string>
|
||||
<string name="main_menu_donate_title">Dona 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Le app non possono più essere installate: devono essere scaricate via browser. Vedi l\'issue #531 per dettagli.</string>
|
||||
<string name="channel_notifications_group_default_name">Predefinita</string>
|
||||
<string name="detail_item_cannot_open_apk">Le app non possono più essere installate: devono essere scaricate tramite browser. Vedi la segnalazione #531 per dettagli.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Mantieni l\'alert per le notifiche a priorità massima</string>
|
||||
<string name="settings_advanced_unifiedpush_title">Attiva UnifiedPush</string>
|
||||
<string name="detail_settings_notifications_open_channels_summary">Bypass Do-Not-Disturb, suoni, etc.</string>
|
||||
<string name="detail_settings_notifications_open_channels_summary">Esclusione Non disturbare (DND), suoni, ecc.</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Continua ad inviare notifiche</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy non si comporterà come un distributore UnifiedPus</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy si comporterà come un distributore UnifiedPush</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_title">Impostazioni di notifica personalizzate</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_on">Usa impostazioni personalizzate per questa iscrizione</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_off">Impostazioni predefinite sono in uso (suoni, bypass Do-Not-Disturb, etc.)</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_off">Utilizzo delle impostazioni predefinite (suoni, esclusione della funzione Non disturbare, ecc.)</string>
|
||||
<string name="detail_settings_notifications_open_channels_title">Configura le impostazioni di notifica</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Invia notifiche solo una volta</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_enabled">Le notifiche a massima priorità continuano ad allertare fino a che non vengono rimosse</string>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
<string name="main_item_status_reconnecting">התחברות מחדש…</string>
|
||||
<string name="main_how_to_intro">לחיצה על + תאפשר ליצור או להירשם לנושא. לאחר מכן התראות תגענה למכשיר שלך בעת שליחת הודעות עם PUT או POST.</string>
|
||||
<string name="main_how_to_link">הוראות מפורטות זמינות ב־ntfy.sh, ובתיעוד.</string>
|
||||
<string name="main_menu_donate_title">תרומה 💸</string>
|
||||
<string name="channel_subscriber_notification_instant_text_two">מנוי לשני נושאים במסירה מיידית</string>
|
||||
<string name="channel_subscriber_notification_instant_text_three">מנוי לשלושה נושאים במסירה מיידית</string>
|
||||
<string name="channel_subscriber_notification_instant_text">מנוי לנושאים במסירה מיידית</string>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="detail_settings_about_header">About</string>
|
||||
<string name="detail_settings_about_topic_url_title">トピックのURL</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">クリップボードにコピーしました</string>
|
||||
<string name="main_menu_donate_title">寄付する💸</string>
|
||||
<string name="detail_item_cannot_open_apk">アプリはインストールできなくなりました。代替手段としてブラウザからダウンロードしてください。詳細は issue #531 をご参照ください。</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_enabled">優先度最高は非表示になるまで通知継続</string>
|
||||
<string name="channel_notifications_group_default_name">デフォルト</string>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="detail_how_to_link">자세한 설명은 ntfy.sh와 docs 페이지에서 찾으실 수 있습니다.</string>
|
||||
<string name="channel_notifications_high_name">알림 (우선순위 높음)</string>
|
||||
<string name="channel_notifications_high_name">우선순위 높음</string>
|
||||
<string name="main_menu_notifications_disabled_forever">알림 음소거됨</string>
|
||||
<string name="channel_subscriber_notification_instant_text_three">즉시 전달 주제 3개 구독중</string>
|
||||
<string name="add_dialog_use_another_server">다른 서버 사용</string>
|
||||
<string name="main_menu_notifications_enabled">알림 켜짐</string>
|
||||
<string name="channel_notifications_default_name">알림 (우선순위 기본)</string>
|
||||
<string name="channel_notifications_max_name">알림 (우선순위 최상)</string>
|
||||
<string name="channel_notifications_default_name">우선순위 기본</string>
|
||||
<string name="channel_notifications_max_name">우선순위 최상</string>
|
||||
<string name="channel_subscriber_service_name">구독 서비스</string>
|
||||
<string name="channel_subscriber_notification_title">알림 수신중</string>
|
||||
<string name="channel_subscriber_notification_instant_text">즉시 전달 주제를 구독함</string>
|
||||
|
|
@ -165,9 +165,9 @@
|
|||
<string name="settings_advanced_connection_protocol_title">연결 프로토콜</string>
|
||||
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON stream over HTTP</string>
|
||||
<string name="detail_settings_appearance_header">표시 설정</string>
|
||||
<string name="channel_notifications_low_name">알림 (우선순위 낮음)</string>
|
||||
<string name="channel_notifications_low_name">우선순위 낮음</string>
|
||||
<string name="user_dialog_button_save">저장</string>
|
||||
<string name="channel_notifications_min_name">알림 (우선순위 최하)</string>
|
||||
<string name="channel_notifications_min_name">우선순위 최하</string>
|
||||
<string name="channel_subscriber_notification_instant_text_two">즉시 전달 주제 2개 구독중</string>
|
||||
<string name="channel_subscriber_notification_instant_text_five">즉시 전달 주제 5개 구독중</string>
|
||||
<string name="channel_subscriber_notification_instant_text_four">즉시 전달 주제 4개 구독중</string>
|
||||
|
|
@ -214,7 +214,7 @@
|
|||
<string name="detail_item_menu_open">파일 열기</string>
|
||||
<string name="detail_item_menu_copy_url_copied">URL이 클립보드에 복사됨</string>
|
||||
<string name="add_dialog_base_urls_dropdown_choose">서비스 URL 선택</string>
|
||||
<string name="detail_how_to_example">예제 (curl 사용):<br></br><tt>$ curl -d \\\"Hi\\\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example">예제 (curl 사용):<br/><tt>$ curl -d \\\"Hi\\\" %1$s</tt></string>
|
||||
<string name="share_content_file_error">파일 정보를 읽을 수 없습니다: %1$s</string>
|
||||
<string name="detail_test_title">테스트: 원한다면 제목을 설정할 수 있습니다.</string>
|
||||
<string name="detail_instant_delivery_disabled">즉시 전달 꺼짐</string>
|
||||
|
|
@ -328,4 +328,5 @@
|
|||
<string name="user_dialog_button_add">사용자 추가</string>
|
||||
<string name="user_dialog_button_delete">사용자 삭제</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_on">이 구독에 사용자 설정 사용</string>
|
||||
<string name="channel_notifications_group_default_name">기본 그룹</string>
|
||||
</resources>
|
||||
|
|
|
|||
8
app/src/main/res/values-mk/strings.xml
Normal file
8
app/src/main/res/values-mk/strings.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="channel_notifications_low_name">Низок приоритет</string>
|
||||
<string name="channel_notifications_min_name">Мин приоритет</string>
|
||||
<string name="channel_notifications_default_name">Стандарден приоритет</string>
|
||||
<string name="channel_notifications_high_name">Висок приоритет</string>
|
||||
<string name="channel_notifications_max_name">Највисок приоритет</string>
|
||||
</resources>
|
||||
|
|
@ -34,7 +34,6 @@
|
|||
<string name="main_menu_notifications_disabled_until">Notifikasi disenyapkan hingga %1$s</string>
|
||||
<string name="main_menu_settings_title">Tetapan</string>
|
||||
<string name="main_menu_report_bug_title">Aduan Kerosakan</string>
|
||||
<string name="main_menu_donate_title">Sumbangan 💸</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Padamkan secara kekal</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Batal</string>
|
||||
<string name="main_item_status_text_one">%1$d notifikasi</string>
|
||||
|
|
|
|||
|
|
@ -324,7 +324,6 @@
|
|||
<string name="detail_settings_appearance_display_name_default_summary">%1$s (standard)</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Kopier til utklippstavlen</string>
|
||||
<string name="detail_settings_appearance_display_name_message">Angi et tilpasset visningsnavn for dette abonnementet. La stå tomt for standard (%1$s).</string>
|
||||
<string name="main_menu_donate_title">Doner 💸</string>
|
||||
<string name="main_banner_websocket_text">Å bytte til WebSockets er den anbefalte måten å koble til serveren på, og kan forbedre batterilevetiden, men kan kreve <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">ytterligere konfigurasjon i proxy-serveren</a>. Dette kan endres i innstillingene.</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Aktiver nå</string>
|
||||
<string name="detail_deep_link_subscribed_toast_message">Abonnerte på emnet %1$s</string>
|
||||
|
|
|
|||
147
app/src/main/res/values-night/colors.xml
Normal file
147
app/src/main/res/values-night/colors.xml
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="md_theme_primary">#84D6C2</color>
|
||||
<color name="md_theme_onPrimary">#00382E</color>
|
||||
<color name="md_theme_primaryContainer">#005144</color>
|
||||
<color name="md_theme_onPrimaryContainer">#A0F2DD</color>
|
||||
<color name="md_theme_secondary">#B1CCC4</color>
|
||||
<color name="md_theme_onSecondary">#1D352F</color>
|
||||
<color name="md_theme_secondaryContainer">#334B45</color>
|
||||
<color name="md_theme_onSecondaryContainer">#CDE8DF</color>
|
||||
<color name="md_theme_tertiary">#AACBE4</color>
|
||||
<color name="md_theme_onTertiary">#113447</color>
|
||||
<color name="md_theme_tertiaryContainer">#2A4A5F</color>
|
||||
<color name="md_theme_onTertiaryContainer">#C8E6FF</color>
|
||||
<color name="md_theme_error">#FFB4AB</color>
|
||||
<color name="md_theme_onError">#690005</color>
|
||||
<color name="md_theme_errorContainer">#93000A</color>
|
||||
<color name="md_theme_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_background">#121212</color>
|
||||
<color name="md_theme_onBackground">#E0E0E0</color>
|
||||
<color name="md_theme_surface">#121212</color>
|
||||
<color name="md_theme_onSurface">#E0E0E0</color>
|
||||
<color name="md_theme_surfaceVariant">#3F4946</color>
|
||||
<color name="md_theme_onSurfaceVariant">#C0C0C0</color>
|
||||
<color name="md_theme_outline">#89938F</color>
|
||||
<color name="md_theme_outlineVariant">#3F4946</color>
|
||||
<color name="md_theme_scrim">#000000</color>
|
||||
<color name="md_theme_inverseSurface">#E0E0E0</color>
|
||||
<color name="md_theme_inverseOnSurface">#2B3230</color>
|
||||
<color name="md_theme_inversePrimary">#076B5B</color>
|
||||
<color name="md_theme_primaryFixed">#A0F2DD</color>
|
||||
<color name="md_theme_onPrimaryFixed">#00201A</color>
|
||||
<color name="md_theme_primaryFixedDim">#84D6C2</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant">#005144</color>
|
||||
<color name="md_theme_secondaryFixed">#CDE8DF</color>
|
||||
<color name="md_theme_onSecondaryFixed">#06201A</color>
|
||||
<color name="md_theme_secondaryFixedDim">#B1CCC4</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant">#334B45</color>
|
||||
<color name="md_theme_tertiaryFixed">#C8E6FF</color>
|
||||
<color name="md_theme_onTertiaryFixed">#001E2E</color>
|
||||
<color name="md_theme_tertiaryFixedDim">#AACBE4</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant">#2A4A5F</color>
|
||||
<color name="md_theme_surfaceDim">#121212</color>
|
||||
<color name="md_theme_surfaceBright">#383838</color>
|
||||
<color name="md_theme_surfaceContainerLowest">#0D0D0D</color>
|
||||
<color name="md_theme_surfaceContainerLow">#1B1B1B</color>
|
||||
<color name="md_theme_surfaceContainer">#1B2023</color>
|
||||
<color name="md_theme_surfaceContainerHigh">#282F33</color>
|
||||
<color name="md_theme_surfaceContainerHighest">#333333</color>
|
||||
<color name="md_theme_primary_mediumContrast">#9AECD7</color>
|
||||
<color name="md_theme_onPrimary_mediumContrast">#002C24</color>
|
||||
<color name="md_theme_primaryContainer_mediumContrast">#4D9F8C</color>
|
||||
<color name="md_theme_onPrimaryContainer_mediumContrast">#000000</color>
|
||||
<color name="md_theme_secondary_mediumContrast">#C7E2D9</color>
|
||||
<color name="md_theme_onSecondary_mediumContrast">#112A24</color>
|
||||
<color name="md_theme_secondaryContainer_mediumContrast">#7C968E</color>
|
||||
<color name="md_theme_onSecondaryContainer_mediumContrast">#000000</color>
|
||||
<color name="md_theme_tertiary_mediumContrast">#C0E1FA</color>
|
||||
<color name="md_theme_onTertiary_mediumContrast">#02293C</color>
|
||||
<color name="md_theme_tertiaryContainer_mediumContrast">#7595AC</color>
|
||||
<color name="md_theme_onTertiaryContainer_mediumContrast">#000000</color>
|
||||
<color name="md_theme_error_mediumContrast">#FFD2CC</color>
|
||||
<color name="md_theme_onError_mediumContrast">#540003</color>
|
||||
<color name="md_theme_errorContainer_mediumContrast">#FF5449</color>
|
||||
<color name="md_theme_onErrorContainer_mediumContrast">#000000</color>
|
||||
<color name="md_theme_background_mediumContrast">#0E1513</color>
|
||||
<color name="md_theme_onBackground_mediumContrast">#DEE4E0</color>
|
||||
<color name="md_theme_surface_mediumContrast">#0E1513</color>
|
||||
<color name="md_theme_onSurface_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceVariant_mediumContrast">#3F4946</color>
|
||||
<color name="md_theme_onSurfaceVariant_mediumContrast">#D4DFDA</color>
|
||||
<color name="md_theme_outline_mediumContrast">#AAB4B0</color>
|
||||
<color name="md_theme_outlineVariant_mediumContrast">#88938F</color>
|
||||
<color name="md_theme_scrim_mediumContrast">#000000</color>
|
||||
<color name="md_theme_inverseSurface_mediumContrast">#DEE4E0</color>
|
||||
<color name="md_theme_inverseOnSurface_mediumContrast">#252B29</color>
|
||||
<color name="md_theme_inversePrimary_mediumContrast">#005245</color>
|
||||
<color name="md_theme_primaryFixed_mediumContrast">#A0F2DD</color>
|
||||
<color name="md_theme_onPrimaryFixed_mediumContrast">#001510</color>
|
||||
<color name="md_theme_primaryFixedDim_mediumContrast">#84D6C2</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant_mediumContrast">#003E34</color>
|
||||
<color name="md_theme_secondaryFixed_mediumContrast">#CDE8DF</color>
|
||||
<color name="md_theme_onSecondaryFixed_mediumContrast">#001510</color>
|
||||
<color name="md_theme_secondaryFixedDim_mediumContrast">#B1CCC4</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant_mediumContrast">#233B35</color>
|
||||
<color name="md_theme_tertiaryFixed_mediumContrast">#C8E6FF</color>
|
||||
<color name="md_theme_onTertiaryFixed_mediumContrast">#00131F</color>
|
||||
<color name="md_theme_tertiaryFixedDim_mediumContrast">#AACBE4</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant_mediumContrast">#18394E</color>
|
||||
<color name="md_theme_surfaceDim_mediumContrast">#0E1513</color>
|
||||
<color name="md_theme_surfaceBright_mediumContrast">#3F4643</color>
|
||||
<color name="md_theme_surfaceContainerLowest_mediumContrast">#040807</color>
|
||||
<color name="md_theme_surfaceContainerLow_mediumContrast">#191F1D</color>
|
||||
<color name="md_theme_surfaceContainer_mediumContrast">#232927</color>
|
||||
<color name="md_theme_surfaceContainerHigh_mediumContrast">#2D3432</color>
|
||||
<color name="md_theme_surfaceContainerHighest_mediumContrast">#393F3D</color>
|
||||
<color name="md_theme_primary_highContrast">#B2FFEB</color>
|
||||
<color name="md_theme_onPrimary_highContrast">#000000</color>
|
||||
<color name="md_theme_primaryContainer_highContrast">#81D2BE</color>
|
||||
<color name="md_theme_onPrimaryContainer_highContrast">#000E0A</color>
|
||||
<color name="md_theme_secondary_highContrast">#DAF6ED</color>
|
||||
<color name="md_theme_onSecondary_highContrast">#000000</color>
|
||||
<color name="md_theme_secondaryContainer_highContrast">#ADC8C0</color>
|
||||
<color name="md_theme_onSecondaryContainer_highContrast">#000E0A</color>
|
||||
<color name="md_theme_tertiary_highContrast">#E3F2FF</color>
|
||||
<color name="md_theme_onTertiary_highContrast">#000000</color>
|
||||
<color name="md_theme_tertiaryContainer_highContrast">#A6C7E0</color>
|
||||
<color name="md_theme_onTertiaryContainer_highContrast">#000D17</color>
|
||||
<color name="md_theme_error_highContrast">#FFECE9</color>
|
||||
<color name="md_theme_onError_highContrast">#000000</color>
|
||||
<color name="md_theme_errorContainer_highContrast">#FFAEA4</color>
|
||||
<color name="md_theme_onErrorContainer_highContrast">#220001</color>
|
||||
<color name="md_theme_background_highContrast">#0E1513</color>
|
||||
<color name="md_theme_onBackground_highContrast">#DEE4E0</color>
|
||||
<color name="md_theme_surface_highContrast">#0E1513</color>
|
||||
<color name="md_theme_onSurface_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceVariant_highContrast">#3F4946</color>
|
||||
<color name="md_theme_onSurfaceVariant_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_outline_highContrast">#E8F2EE</color>
|
||||
<color name="md_theme_outlineVariant_highContrast">#BBC5C1</color>
|
||||
<color name="md_theme_scrim_highContrast">#000000</color>
|
||||
<color name="md_theme_inverseSurface_highContrast">#DEE4E0</color>
|
||||
<color name="md_theme_inverseOnSurface_highContrast">#000000</color>
|
||||
<color name="md_theme_inversePrimary_highContrast">#005245</color>
|
||||
<color name="md_theme_primaryFixed_highContrast">#A0F2DD</color>
|
||||
<color name="md_theme_onPrimaryFixed_highContrast">#000000</color>
|
||||
<color name="md_theme_primaryFixedDim_highContrast">#84D6C2</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant_highContrast">#001510</color>
|
||||
<color name="md_theme_secondaryFixed_highContrast">#CDE8DF</color>
|
||||
<color name="md_theme_onSecondaryFixed_highContrast">#000000</color>
|
||||
<color name="md_theme_secondaryFixedDim_highContrast">#B1CCC4</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant_highContrast">#001510</color>
|
||||
<color name="md_theme_tertiaryFixed_highContrast">#C8E6FF</color>
|
||||
<color name="md_theme_onTertiaryFixed_highContrast">#000000</color>
|
||||
<color name="md_theme_tertiaryFixedDim_highContrast">#AACBE4</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant_highContrast">#00131F</color>
|
||||
<color name="md_theme_surfaceDim_highContrast">#0E1513</color>
|
||||
<color name="md_theme_surfaceBright_highContrast">#4B514F</color>
|
||||
<color name="md_theme_surfaceContainerLowest_highContrast">#000000</color>
|
||||
<color name="md_theme_surfaceContainerLow_highContrast">#1B211F</color>
|
||||
<color name="md_theme_surfaceContainer_highContrast">#2B3230</color>
|
||||
<color name="md_theme_surfaceContainerHigh_highContrast">#363D3A</color>
|
||||
<color name="md_theme_surfaceContainerHighest_highContrast">#424846</color>
|
||||
|
||||
<color name="action_bar">#1B2023</color> <!-- md_theme_surfaceContainer (dark) - matches card color -->
|
||||
<color name="detail_activity_background">#121212</color> <!-- Black for detail activity in dark mode -->
|
||||
</resources>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--
|
||||
This file contains only overrides for the dark theme.
|
||||
Also see "ui/Colors.kt" for colors that have to be defined in code.
|
||||
|
||||
Resources:
|
||||
- https://material.io/design/color/dark-theme.html
|
||||
- https://material.io/develop/android/theming/dark
|
||||
- https://developer.android.com/codelabs/basic-android-kotlin-training-change-app-theme#4
|
||||
- https://developer.android.com/guide/topics/ui/look-and-feel/themes
|
||||
-->
|
||||
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/teal_light</item>
|
||||
<item name="colorAccent">@color/teal_light</item> <!-- checkboxes, text fields -->
|
||||
<item name="android:colorBackground">@color/black_900</item> <!-- background -->
|
||||
<item name="android:statusBarColor">@color/black_900</item>
|
||||
<item name="actionModeBackground">@color/black_900</item>
|
||||
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
|
||||
|
||||
<!-- Action bar background & text color -->
|
||||
<item name="colorSurface">@color/black_800b</item>
|
||||
<item name="colorOnSurface">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="DangerText" parent="@android:style/TextAppearance">
|
||||
<item name="android:textColor">@color/red_light</item>
|
||||
</style>
|
||||
|
||||
<style name="FloatingActionButton" parent="@style/Widget.MaterialComponents.FloatingActionButton">
|
||||
<item name="tint">@color/black_900</item>
|
||||
<item name="backgroundTint">@color/teal_light</item>
|
||||
</style>
|
||||
|
||||
<style name="CardView" parent="@style/Widget.MaterialComponents.CardView">
|
||||
<item name="cardBackgroundColor">@color/black_800b</item>
|
||||
</style>
|
||||
|
||||
<style name="CardViewBackground">
|
||||
<item name="android:background">@color/black_900</item>
|
||||
</style>
|
||||
</resources>
|
||||
12
app/src/main/res/values-night/themes.xml
Normal file
12
app/src/main/res/values-night/themes.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<resources>
|
||||
<!-- Action mode overrides for dark mode -->
|
||||
<style name="ActionMode" parent="@style/Widget.AppCompat.ActionMode">
|
||||
<item name="background">?attr/colorSurface</item>
|
||||
<item name="titleTextStyle">@style/ActionModeTitle</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionModeTitle" parent="@style/TextAppearance.AppCompat.Widget.ActionMode.Title">
|
||||
<item name="android:textColor">?attr/colorOnSurface</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
|
|
@ -328,7 +328,6 @@
|
|||
<string name="main_banner_websocket_button_enable_now">Nu inschakelen</string>
|
||||
<string name="main_banner_websocket_text">WebSockets is de aangeraden manier om te verbinden met uw server en kan batterij verbruik verminderen. Het kan <a href="https://ntfy.sh/docs/config/#nginxapache2caddy"> extra configuratie in uw proxy</a> vereisen. Dit kan omgeschakeld worden in de instellingen.</string>
|
||||
<string name="channel_notifications_group_default_name">Standaard</string>
|
||||
<string name="main_menu_donate_title">Doneer 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Apps kunnen niet meer worden geïnstalleerd. Download deze via de browser. Raadpleeg issue #531 voor meer details.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Behoud meldingen voor hoogste prioriteit</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_enabled">Max prioriteit berichten geven continue een melding totdat deze worden gesloten</string>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="main_banner_websocket_button_dismiss">Odrzuć</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Aktywuj teraz</string>
|
||||
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Użyj strumienia JSON przez HTTP, aby połączyć się z serwerem. Ta metoda jest sprawdzona, ale może zużywać więcej baterii.</string>
|
||||
<string name="main_menu_donate_title">Wspomóż💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Aplikacja nie może zostać zainstalowana. Pobierz ją poprzez przeglądarkę. Sprawdź problem #531 po więcej informacji.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Nadal wysyłaj powiadomienia dla najwyższych priorytetów</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_title">Własne ustawienia powiadomień</string>
|
||||
|
|
|
|||
|
|
@ -324,7 +324,6 @@
|
|||
<string name="add_dialog_base_urls_dropdown_clear">Limpar URL do serviço</string>
|
||||
<string name="main_banner_websocket_button_enable_now">Habilitar agora</string>
|
||||
<string name="channel_notifications_group_default_name">Padrão</string>
|
||||
<string name="main_menu_donate_title">Doar 💸</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">As notificações de prioridade máxima alertam apenas uma vez</string>
|
||||
<string name="detail_settings_notifications_open_channels_title">Configurar configurações de notificação</string>
|
||||
<string name="detail_settings_notifications_open_channels_summary">Ignorar o Não Perturbe, sons, etc.</string>
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@
|
|||
<string name="add_dialog_login_description">Esse tópico necessita autenticação. Por favor, insira um nome de utilizador e palavra-passe.</string>
|
||||
<string name="add_dialog_login_new_user">Novo utilizador</string>
|
||||
<string name="add_dialog_base_urls_dropdown_choose">Escolha URL de serviço</string>
|
||||
<string name="detail_how_to_example">Exemplo (utilizando curl): <br></br><tt>$ curl -d \"Olá\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Exemplo (usando curl):<br/><tt>$ curl -d \"Olá\" %1$s</tt> ]]></string>
|
||||
<string name="detail_delete_dialog_message">Deseja anular a subscrição deste tópico e eliminar todas as notificações recebidas\?</string>
|
||||
<string name="detail_test_message">Esta é uma notificação de teste da aplicação Android do ntfy. Tem uma prioridade de nível %1$d. Se enviar outra notificação, poderá ser diferente.</string>
|
||||
<string name="detail_test_message_error_too_large">Não foi possível enviar a mensagem: O anexo é grande demais.</string>
|
||||
|
|
@ -258,7 +258,6 @@
|
|||
<string name="settings_general_dark_mode_summary_light">Modo claro</string>
|
||||
<string name="settings_general_dark_mode_title">Modo escuro</string>
|
||||
<string name="settings_general_dark_mode_summary_system">Usar a predefinição do sistema</string>
|
||||
<string name="main_menu_donate_title">Doar 💸</string>
|
||||
<string name="settings_backup_restore_restore_failed">Falha ao restaurar %1$s</string>
|
||||
<string name="settings_advanced_header">Avançado</string>
|
||||
<string name="settings_advanced_broadcast_title">Messagens de transmissão</string>
|
||||
|
|
@ -343,4 +342,11 @@
|
|||
<string name="settings_advanced_unifiedpush_title">Habilitar UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy atuará como distribuidora UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy não atuará como distribuidora UnifiedPush</string>
|
||||
<string name="main_banner_websocket_reconnect_text">Para garantir que os WebSockets se reconectem em segundo plano, conceda a permissão de Alarmes e Lembretes à aplicação ntfy</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Lembrar mais tarde</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Ignorar</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Autorizar agora</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Alarmes exactos</string>
|
||||
<string name="settings_advanced_exact_alarms_true">O ntfy pode agendar alarmes exatos. Alarmes exatos são necessários para reconectar os WebSockets em segundo plano. Clique para revogar a permissão.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">O ntfy não pode agendar alarmes exatos. Alarmes exatos são necessários para reconectar os WebSockets em segundo plano. Clique para conceder a permissão.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -162,7 +162,6 @@
|
|||
<string name="main_menu_report_bug_title">Raportează o problemă</string>
|
||||
<string name="main_menu_docs_title">Citește documentația</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Dezabonează-te de la topicele selectate și șterge notificările permanent\?</string>
|
||||
<string name="main_menu_donate_title">Donează 💸</string>
|
||||
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
|
||||
<string name="main_add_button_description">Adaugă abonament</string>
|
||||
<string name="main_item_status_text_not_one">%1$d notificări</string>
|
||||
|
|
@ -313,7 +312,7 @@
|
|||
<string name="add_dialog_login_error_not_authorized">Logare eșuată. Utilizatorul %1$s nu este autorizat.</string>
|
||||
<string name="add_dialog_login_new_user">Utilizator nou</string>
|
||||
<string name="detail_no_notifications_text">Nu ai primit încă notificări pentru acest topic.</string>
|
||||
<string name="detail_how_to_example">Exemplu (folosing curl):<br></br><tt>$ curl -d \"Salut\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example">Exemplu (folosing curl):<br/><tt>$ curl -d \"Salut\" %1$s</tt></string>
|
||||
<string name="detail_delete_dialog_cancel">Anulează</string>
|
||||
<string name="detail_test_title">Test: Poți specifica un titlu dacă dorești.</string>
|
||||
<string name="detail_test_message">Această este o notificare de test de la aplicația ntfy pentru Android. Are nivelul priorității %1$d. Dacă trimiți altă notificare, s-ar putea să arate altfel.</string>
|
||||
|
|
@ -343,4 +342,9 @@
|
|||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy va avea rol de distribuitor UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_title">Activează UnifiedPush</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy nu va avea rol de distribuitor UnifiedPush</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Întreabă mai târziu</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Respinge</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Alarme exacte</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy poate programa alarme exacte. Alarmele exacte sunt necesare pentru a reconecta WebSocket-urile în fundal. Faceți clic pentru a revoca permisiunea.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy nu poate programa alarme exacte. Alarmele exacte sunt necesare pentru a reconecta WebSockets în fundal. Faceți clic pentru a acorda permisiunea.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<string name="detail_delete_dialog_permanently_delete">Удалить навсегда</string>
|
||||
<string name="detail_delete_dialog_cancel">Отмена</string>
|
||||
<string name="detail_test_title">Тест: Вы можете установить заголовок, если хотите.</string>
|
||||
<string name="detail_how_to_example">Пример (используя curl):<br></br><tt>$ curl -d \"Привет\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Пример (используя curl):<br/><tt>$ curl -d \"Привет\" %1$s</tt> ]]></string>
|
||||
<string name="detail_clear_dialog_message">Удалить все уведомления в этой теме\?</string>
|
||||
<string name="detail_clear_dialog_permanently_delete">Удалить навсегда</string>
|
||||
<string name="detail_test_message_error">Не получилось отправить сообщение: %1$s</string>
|
||||
|
|
@ -313,7 +313,6 @@
|
|||
<string name="detail_item_cannot_open_apk">Установка приложений через уведомления больше не поддерживается. Скачайте приложение через браузер. Подробности смотрите в отчёте ntfy #531.</string>
|
||||
<string name="detail_settings_appearance_icon_set_title">Иконка подписки</string>
|
||||
<string name="detail_settings_appearance_icon_set_summary">Использовать иконку для отображения в уведомлениях</string>
|
||||
<string name="main_menu_donate_title">Пожертвовать 💸</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">Уведомления с наивысшим приоритетом будут давать о себе знать только один раз</string>
|
||||
<string name="detail_settings_notifications_instant_summary_off">Уведомления будут доставляться с помощью Firebase. Могут быть задержки с доставкой, но потребляется меньше энергии.</string>
|
||||
<string name="add_dialog_base_urls_dropdown_clear">Очистить URL-адрес сервера</string>
|
||||
|
|
@ -343,4 +342,11 @@
|
|||
<string name="detail_settings_notifications_dedicated_channels_summary_on">Используются пользовательские настройки для этой подписки</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Уведомлять только один раз</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Продолжать уведомлять при наивысшем приоритете</string>
|
||||
<string name="main_banner_websocket_reconnect_text">Чтобы WebSockets работал в фоновом режиме, проставьте ntfy права «Будильники и напоминания»</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Спроси потом</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Закрыть</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Предоставить</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Точные оповещения</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy может выставлять точные оповещения. Точные оповещения необходимы для переподключения WebSockets в фоновом режиме. Нажмите, чтобы отозвать разрешение.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy может выставлять точные оповещения. Точные оповещения необходимы для переподключения WebSockets в фоновом режиме. Нажмите, чтобы дать разрешение.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -282,7 +282,6 @@
|
|||
<string name="main_menu_rate_title">Ohodnotiť aplikáciu ⭐</string>
|
||||
<string name="main_menu_docs_title">Prečítať dokumentáciu</string>
|
||||
<string name="main_menu_notifications_disabled_until">Oznámenia stlmené do %1$s</string>
|
||||
<string name="main_menu_donate_title">Prispieť 💸</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Odhlásiť odber z vybraných tém a natrvalo vymazať všetky oznámenia\?</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Vymazať natrvalo</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">Odhlásiť odber</string>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
<string name="add_dialog_base_urls_dropdown_clear">Rensa tjänstens URL</string>
|
||||
<string name="detail_no_notifications_text">Du har inte fått några meddelanden för detta ämne ännu.</string>
|
||||
<string name="detail_how_to_intro">För att skicka meddelanden till det här ämnet, PUT eller POST till ämnesadressen.</string>
|
||||
<string name="detail_how_to_example">Exempel (med curl):<br></br><tt>$ curl -d \"Hej\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Exempel (med curl):<br/><tt>$ curl -d \"Hej\" %1$s</tt> ]]></string>
|
||||
<string name="detail_how_to_link">Detaljerade instruktioner finns på ntfy.sh och i dokumentationen.</string>
|
||||
<string name="detail_clear_dialog_message">Ta bort alla meddelanden i det här ämnet\?</string>
|
||||
<string name="detail_clear_dialog_permanently_delete">Ta bort permanent</string>
|
||||
|
|
@ -113,7 +113,6 @@
|
|||
<string name="detail_settings_title">Prenumerationsinställningar</string>
|
||||
<string name="share_title">Dela</string>
|
||||
<string name="share_menu_send">Dela</string>
|
||||
<string name="main_menu_donate_title">Donera 💸</string>
|
||||
<string name="detail_item_snack_undo">Ångra</string>
|
||||
<string name="detail_item_menu_open">Öppna fil</string>
|
||||
<string name="detail_item_menu_delete">Ta bort fil</string>
|
||||
|
|
@ -343,4 +342,11 @@
|
|||
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Meddela endast en gång</string>
|
||||
<string name="detail_settings_global_setting_title">Använd de globala inställningarna</string>
|
||||
<string name="detail_settings_appearance_icon_remove_summary">Ikon som visas i meddelanden för detta ämne</string>
|
||||
<string name="main_banner_websocket_reconnect_text">För att säkerställa att WebSockets återansluter i bakgrunden, bevilja behörigheten Alarm & Påminnelser till ntfy</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Fråga senare</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Avfärda</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Bevilja nu</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Exakta larm</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy kan schemalägga exakta larm. Exakta larm krävs för att återansluta WebSockets i bakgrunden. Klicka för att återkalla behörigheten.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy kan inte schemalägga exakta larm. Exakta larm krävs för att återansluta WebSockets i bakgrunden. Klicka för att bevilja behörigheten.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
<string name="main_menu_report_bug_title">ஒரு பிழையைப் புகாரளிக்கவும்</string>
|
||||
<string name="main_menu_docs_title">ஆவணத்தைப் படியுங்கள்</string>
|
||||
<string name="main_menu_rate_title">பயன்பாட்டை மதிப்பிடுங்கள்</string>
|
||||
<string name="main_menu_donate_title">நன்கொடை</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">குழுவிலகவும்</string>
|
||||
<string name="main_action_mode_delete_dialog_message">தேர்ந்தெடுக்கப்பட்ட தலைப்பு (கள்) இலிருந்து குழுவிலகவும், அனைத்து அறிவிப்புகளையும் நிரந்தரமாக நீக்கவா?</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">ரத்துசெய்</string>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
<string name="main_menu_report_bug_title">รายงานปัญหา(Bug)</string>
|
||||
<string name="main_menu_docs_title">อ่านเอกสาร</string>
|
||||
<string name="main_menu_rate_title">ให้คะแนนแอป ⭐</string>
|
||||
<string name="main_menu_donate_title">บริจาค 💸</string>
|
||||
<string name="main_action_mode_menu_unsubscribe">ยกเลิกการสมัครรับ</string>
|
||||
<string name="main_action_mode_delete_dialog_message">ต้องการยกเลิกการสมัครจากหัวข้อที่เลือกและลบการแจ้งเตือนทั้งหมดอย่างถาวรใช่ไหม</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">ลบถาวร</string>
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
<string name="refresh_message_no_results">Her şey güncel</string>
|
||||
<string name="main_menu_notifications_disabled_until">Bildirimler şu zamana kadar sessize alındı: %1$s</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_more">%1$d konuya abone olundu</string>
|
||||
<string name="refresh_message_error">%1$d abonelik yenilenemedi
|
||||
\n
|
||||
\n%2$s</string>
|
||||
<string name="refresh_message_error">%1$d abonelik yenilenemedi\n\n%2$s</string>
|
||||
<string name="refresh_message_error_one">Abonelik yenilenemedi: %1$s</string>
|
||||
<string name="main_action_bar_title">Abone olunan konular</string>
|
||||
<string name="main_menu_notifications_enabled">Bildirimler açık</string>
|
||||
|
|
@ -209,7 +207,7 @@
|
|||
<string name="main_item_date_yesterday">dün</string>
|
||||
<string name="main_banner_battery_button_dismiss">Kapat</string>
|
||||
<string name="main_banner_battery_button_fix_now">Şimdi düzelt</string>
|
||||
<string name="detail_how_to_example">Örnek (curl kullanarak):<br></br><tt>$ curl -d \"Merhaba\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ Örnek (curl kullanarak):<br/><tt>$ curl -d "Merhaba" %1$s</tt> ]]></string>
|
||||
<string name="detail_delete_dialog_permanently_delete">Kalıcı olarak sil</string>
|
||||
<string name="detail_test_message_error_unauthorized_user">Mesaj gönderilemiyor: \"%1$s\" kullanıcısı yetkilendirilmedi.</string>
|
||||
<string name="detail_how_to_link">Ayrıntılı talimatlar ntfy.sh adrsimde ve belgelerde bulunabilir.</string>
|
||||
|
|
@ -327,7 +325,6 @@
|
|||
<string name="detail_settings_about_header">Hakkında</string>
|
||||
<string name="detail_settings_about_topic_url_title">Konu URL\'si</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Panoya kopyalandı</string>
|
||||
<string name="main_menu_donate_title">Bağış yap 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">Uygulamalar artık kurulamıyor. Bunun yerine tarayıcı üzerinden indirin. Ayrıntılar için sorun #531\'e bakın.</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">En yüksek öncelikli bildirimler yalnızca bir kez uyarı verir</string>
|
||||
<string name="detail_settings_notifications_dedicated_channels_summary_on">Bu abonelik için özel ayarları kullan</string>
|
||||
|
|
@ -343,4 +340,11 @@
|
|||
<string name="settings_advanced_unifiedpush_title">UnifiedPush\'u etkinleştir</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy bir UnifiedPush dağıtıcısı olarak davranmayacaktır</string>
|
||||
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy bir UnifiedPush dağıtıcısı olarak davranacaktır</string>
|
||||
<string name="main_banner_websocket_reconnect_text">WebSocket bağlantılarının arka planda yeniden bağlanmasını sağlamak için ntfy uygulamasına Alarm ve Hatırlatıcılar iznini verin</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">Daha Sonra Hatırlat</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">Yoksay</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">Şimdi izin ver</string>
|
||||
<string name="settings_advanced_exact_alarms_title">Kesin alarmlar</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy, kesin alarmlar planlayabilir. Kesin alarmlar, WebSocket’lerin arka planda yeniden bağlanması için gereklidir. İzni geri almak için tıklayın.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy, kesin alarmlar planlayamaz. Kesin alarmlar, WebSocket’lerin arka planda yeniden bağlanması için gereklidir. İzni vermek için tıklayın.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -331,7 +331,6 @@
|
|||
<string name="detail_settings_notifications_dedicated_channels_summary_off">Використання налаштувань за замовчуванням (звуки, \"Не турбувати\" тощо)</string>
|
||||
<string name="detail_settings_notifications_open_channels_summary">Перевизначення режиму \"Не турбувати\" (DND), звуки тощо.</string>
|
||||
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Продовжувати сповіщати</string>
|
||||
<string name="main_menu_donate_title">Пожертвувати 💸</string>
|
||||
<string name="settings_notifications_insistent_max_priority_title">Безперервне сповіщення для найвищого пріоритету</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_enabled">Сповіщення з максимальним пріоритетом безперервно сповіщають, доки не будуть закриті</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_disabled">Сповіщення з максимальним пріоритетом сповіщають лише один раз</string>
|
||||
|
|
|
|||
|
|
@ -248,7 +248,6 @@
|
|||
<string name="channel_subscriber_notification_instant_text_three">Uchta darhol yuborish mavzulariga obuna bo‘ldik</string>
|
||||
<string name="main_menu_notifications_disabled_until">Bildirishnomalar %1$s gacha o‘chirilgan</string>
|
||||
<string name="channel_subscriber_notification_noinstant_text_five">Beshta mavzuga obuna bo‘ldik</string>
|
||||
<string name="main_menu_donate_title">Xayriya qiling 💸</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Bekor qilish</string>
|
||||
<string name="add_dialog_use_another_server_description">Boshqa serverlardan mavzularga obuna bo‘lish uchun quyida URL manzillarini kiriting.</string>
|
||||
<string name="add_dialog_login_description">Ushbu mavzu tizimga kirishni talab qiladi. Iltimos, foydalanuvchi nomi va parolni kiriting.</string>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
<string name="channel_subscriber_notification_title">Chờ thông báo</string>
|
||||
<string name="refresh_message_result">Đã nhận %1$d thông báo</string>
|
||||
<string name="main_action_mode_delete_dialog_permanently_delete">Xóa vĩnh viễn</string>
|
||||
<string name="main_menu_donate_title">Quyên góp 💸</string>
|
||||
<string name="main_action_mode_delete_dialog_cancel">Hủy</string>
|
||||
<string name="main_action_mode_delete_dialog_message">Hủy đăng kí các chủ đề đã chọn và xóa tất cả thông báo?</string>
|
||||
<string name="main_banner_websocket_button_remind_later">Hỏi sau</string>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@
|
|||
<string name="detail_settings_about_header">关于</string>
|
||||
<string name="detail_settings_about_topic_url_title">主题 URL</string>
|
||||
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">已复制到剪贴板</string>
|
||||
<string name="main_menu_donate_title">捐赠 💸</string>
|
||||
<string name="detail_item_cannot_open_apk">无法再安装应用。 请通过浏览器下载。 有关详细信息,请参阅问题 #531。</string>
|
||||
<string name="channel_notifications_group_default_name">默认</string>
|
||||
<string name="settings_notifications_insistent_max_priority_summary_enabled">持续以最高优先级通知进行提醒,直至取消</string>
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@
|
|||
<string name="detail_settings_notifications_instant_title">即時通知</string>
|
||||
<string name="detail_settings_global_setting_suffix">使用全域設定</string>
|
||||
<string name="user_dialog_title_add">新增使用者</string>
|
||||
<string name="main_menu_donate_title">捐獻 💸</string>
|
||||
<string name="detail_item_snack_undo">復原</string>
|
||||
<string name="detail_item_download_info_downloading_x_percent">已下載 %1$d%%</string>
|
||||
<string name="detail_menu_enable_instant">啓用即時通知</string>
|
||||
|
|
@ -213,7 +212,7 @@
|
|||
<string name="detail_item_saved_successfully">儲存為 \"Downloads\" 資料中的 \"%1$s\"</string>
|
||||
<string name="detail_test_message_error_unauthorized_user">不能夠發布信息:用戶 %1$s 不被授權。</string>
|
||||
<string name="detail_how_to_intro">PUT 或 POST 主題網址以傳送通訊。</string>
|
||||
<string name="detail_how_to_example">例如(使用 curl): <br></br><tt>$ curl -d \"Hi\" %1$s</tt></string>
|
||||
<string name="detail_how_to_example"><![CDATA[ 例如(使用 curl): <br/><tt>$ curl -d "Hi" %1$s</tt>]]></string>
|
||||
<string name="detail_test_message_error">不能夠傳送訊息:%1$s</string>
|
||||
<string name="detail_item_tags">標籤:%1$s</string>
|
||||
<string name="detail_instant_delivery_enabled">啟動即時傳送</string>
|
||||
|
|
@ -343,4 +342,11 @@
|
|||
<string name="detail_settings_appearance_icon_error_saving">無法保存圖標:%1$s</string>
|
||||
<string name="detail_settings_global_setting_title">使用全局設置</string>
|
||||
<string name="user_dialog_description_edit">您可以編輯該用戶的用戶名和密碼,或刪除該用戶。</string>
|
||||
<string name="main_banner_websocket_reconnect_text">為確保 WebSocket 能在背景重新連線,請授予 ntfy「鬧鐘與提醒」權限</string>
|
||||
<string name="main_banner_websocket_reconnect_button_dismiss">關閉</string>
|
||||
<string name="main_banner_websocket_reconnect_button_remind_later">稍後再問</string>
|
||||
<string name="main_banner_websocket_reconnect_button_enable_now">立即授權</string>
|
||||
<string name="settings_advanced_exact_alarms_title">精準提醒</string>
|
||||
<string name="settings_advanced_exact_alarms_true">ntfy 可以排程精準提醒。精準提醒是讓 WebSocket 能在背景重新連線的必要條件。點擊以撤銷此權限。</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy 無法排程精準提醒。精準提醒是讓 WebSocket 能在背景重新連線的必要條件。點擊以授予此權限。</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,151 @@
|
|||
<!--?xml version="1.0" encoding="UTF-8"?-->
|
||||
<resources>
|
||||
<color name="black">#ff000000</color>
|
||||
<color name="black_900">#121212</color> <!-- Main dark mode surface color, as per style guide -->
|
||||
<color name="black_800b">#1b2023</color> <!-- Action bar & item selection (dark mode); this has a touch of blue! -->
|
||||
<color name="black_700b">#282F33</color> <!-- Card selection (dark mode); this has a touch of blue! -->
|
||||
<color name="gray_500">#dddddd</color> <!-- Card selection (light mode) -->
|
||||
<color name="gray_400">#eeeeee</color> <!-- Item selection (light mode) -->
|
||||
<color name="white">#ffffffff</color>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color name="md_theme_primary">#338574</color>
|
||||
<color name="md_theme_onPrimary">#FFFFFF</color>
|
||||
<color name="md_theme_primaryContainer">#A0F2DD</color>
|
||||
<color name="md_theme_onPrimaryContainer">#005144</color>
|
||||
<color name="md_theme_secondary">#4B635C</color>
|
||||
<color name="md_theme_onSecondary">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryContainer">#CDE8DF</color>
|
||||
<color name="md_theme_onSecondaryContainer">#334B45</color>
|
||||
<color name="md_theme_tertiary">#436278</color>
|
||||
<color name="md_theme_onTertiary">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryContainer">#C8E6FF</color>
|
||||
<color name="md_theme_onTertiaryContainer">#2A4A5F</color>
|
||||
<color name="md_theme_error">#BA1A1A</color>
|
||||
<color name="md_theme_onError">#FFFFFF</color>
|
||||
<color name="md_theme_errorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_onErrorContainer">#93000A</color>
|
||||
<color name="md_theme_background">#FFFFFF</color>
|
||||
<color name="md_theme_onBackground">#171D1B</color>
|
||||
<color name="md_theme_surface">#FFFFFF</color>
|
||||
<color name="md_theme_onSurface">#171D1B</color>
|
||||
<color name="md_theme_surfaceVariant">#E0E0E0</color>
|
||||
<color name="md_theme_onSurfaceVariant">#3F4946</color>
|
||||
<color name="md_theme_outline">#6F7976</color>
|
||||
<color name="md_theme_outlineVariant">#C0C0C0</color>
|
||||
<color name="md_theme_scrim">#000000</color>
|
||||
<color name="md_theme_inverseSurface">#2B3230</color>
|
||||
<color name="md_theme_inverseOnSurface">#F0F0F0</color>
|
||||
<color name="md_theme_inversePrimary">#84D6C2</color>
|
||||
<color name="md_theme_primaryFixed">#A0F2DD</color>
|
||||
<color name="md_theme_onPrimaryFixed">#00201A</color>
|
||||
<color name="md_theme_primaryFixedDim">#84D6C2</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant">#005144</color>
|
||||
<color name="md_theme_secondaryFixed">#CDE8DF</color>
|
||||
<color name="md_theme_onSecondaryFixed">#06201A</color>
|
||||
<color name="md_theme_secondaryFixedDim">#B1CCC4</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant">#334B45</color>
|
||||
<color name="md_theme_tertiaryFixed">#C8E6FF</color>
|
||||
<color name="md_theme_onTertiaryFixed">#001E2E</color>
|
||||
<color name="md_theme_tertiaryFixedDim">#AACBE4</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant">#2A4A5F</color>
|
||||
<color name="md_theme_surfaceDim">#E0E0E0</color>
|
||||
<color name="md_theme_surfaceBright">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceContainerLowest">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceContainerLow">#F5F5F5</color>
|
||||
<color name="md_theme_surfaceContainer">#F0F0F0</color>
|
||||
<color name="md_theme_surfaceContainerHigh">#EEEEEE</color>
|
||||
<color name="md_theme_surfaceContainerHighest">#E0E0E0</color>
|
||||
<color name="md_theme_primary_mediumContrast">#003E34</color>
|
||||
<color name="md_theme_onPrimary_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_primaryContainer_mediumContrast">#237A69</color>
|
||||
<color name="md_theme_onPrimaryContainer_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondary_mediumContrast">#233B35</color>
|
||||
<color name="md_theme_onSecondary_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryContainer_mediumContrast">#59726B</color>
|
||||
<color name="md_theme_onSecondaryContainer_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiary_mediumContrast">#18394E</color>
|
||||
<color name="md_theme_onTertiary_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryContainer_mediumContrast">#517187</color>
|
||||
<color name="md_theme_onTertiaryContainer_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_error_mediumContrast">#740006</color>
|
||||
<color name="md_theme_onError_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_errorContainer_mediumContrast">#CF2C27</color>
|
||||
<color name="md_theme_onErrorContainer_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_background_mediumContrast">#F5FBF7</color>
|
||||
<color name="md_theme_onBackground_mediumContrast">#171D1B</color>
|
||||
<color name="md_theme_surface_mediumContrast">#F5FBF7</color>
|
||||
<color name="md_theme_onSurface_mediumContrast">#0C1211</color>
|
||||
<color name="md_theme_surfaceVariant_mediumContrast">#DBE5E0</color>
|
||||
<color name="md_theme_onSurfaceVariant_mediumContrast">#2F3835</color>
|
||||
<color name="md_theme_outline_mediumContrast">#4B5551</color>
|
||||
<color name="md_theme_outlineVariant_mediumContrast">#656F6C</color>
|
||||
<color name="md_theme_scrim_mediumContrast">#000000</color>
|
||||
<color name="md_theme_inverseSurface_mediumContrast">#2B3230</color>
|
||||
<color name="md_theme_inverseOnSurface_mediumContrast">#ECF2EF</color>
|
||||
<color name="md_theme_inversePrimary_mediumContrast">#84D6C2</color>
|
||||
<color name="md_theme_primaryFixed_mediumContrast">#237A69</color>
|
||||
<color name="md_theme_onPrimaryFixed_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_primaryFixedDim_mediumContrast">#006051</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryFixed_mediumContrast">#59726B</color>
|
||||
<color name="md_theme_onSecondaryFixed_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryFixedDim_mediumContrast">#415A53</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryFixed_mediumContrast">#517187</color>
|
||||
<color name="md_theme_onTertiaryFixed_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryFixedDim_mediumContrast">#39586E</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceDim_mediumContrast">#C1C8C5</color>
|
||||
<color name="md_theme_surfaceBright_mediumContrast">#F5FBF7</color>
|
||||
<color name="md_theme_surfaceContainerLowest_mediumContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceContainerLow_mediumContrast">#EFF5F1</color>
|
||||
<color name="md_theme_surfaceContainer_mediumContrast">#E3EAE6</color>
|
||||
<color name="md_theme_surfaceContainerHigh_mediumContrast">#D8DEDB</color>
|
||||
<color name="md_theme_surfaceContainerHighest_mediumContrast">#CDD3D0</color>
|
||||
<color name="md_theme_primary_highContrast">#00332A</color>
|
||||
<color name="md_theme_onPrimary_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_primaryContainer_highContrast">#005346</color>
|
||||
<color name="md_theme_onPrimaryContainer_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondary_highContrast">#18302B</color>
|
||||
<color name="md_theme_onSecondary_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryContainer_highContrast">#364E47</color>
|
||||
<color name="md_theme_onSecondaryContainer_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiary_highContrast">#0B2F43</color>
|
||||
<color name="md_theme_onTertiary_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryContainer_highContrast">#2D4D62</color>
|
||||
<color name="md_theme_onTertiaryContainer_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_error_highContrast">#600004</color>
|
||||
<color name="md_theme_onError_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_errorContainer_highContrast">#98000A</color>
|
||||
<color name="md_theme_onErrorContainer_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_background_highContrast">#F5FBF7</color>
|
||||
<color name="md_theme_onBackground_highContrast">#171D1B</color>
|
||||
<color name="md_theme_surface_highContrast">#F5FBF7</color>
|
||||
<color name="md_theme_onSurface_highContrast">#000000</color>
|
||||
<color name="md_theme_surfaceVariant_highContrast">#DBE5E0</color>
|
||||
<color name="md_theme_onSurfaceVariant_highContrast">#000000</color>
|
||||
<color name="md_theme_outline_highContrast">#252E2B</color>
|
||||
<color name="md_theme_outlineVariant_highContrast">#424B48</color>
|
||||
<color name="md_theme_scrim_highContrast">#000000</color>
|
||||
<color name="md_theme_inverseSurface_highContrast">#2B3230</color>
|
||||
<color name="md_theme_inverseOnSurface_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_inversePrimary_highContrast">#84D6C2</color>
|
||||
<color name="md_theme_primaryFixed_highContrast">#005346</color>
|
||||
<color name="md_theme_onPrimaryFixed_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_primaryFixedDim_highContrast">#003A30</color>
|
||||
<color name="md_theme_onPrimaryFixedVariant_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryFixed_highContrast">#364E47</color>
|
||||
<color name="md_theme_onSecondaryFixed_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_secondaryFixedDim_highContrast">#1F3731</color>
|
||||
<color name="md_theme_onSecondaryFixedVariant_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryFixed_highContrast">#2D4D62</color>
|
||||
<color name="md_theme_onTertiaryFixed_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_tertiaryFixedDim_highContrast">#14364A</color>
|
||||
<color name="md_theme_onTertiaryFixedVariant_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceDim_highContrast">#B4BAB7</color>
|
||||
<color name="md_theme_surfaceBright_highContrast">#F5FBF7</color>
|
||||
<color name="md_theme_surfaceContainerLowest_highContrast">#FFFFFF</color>
|
||||
<color name="md_theme_surfaceContainerLow_highContrast">#ECF2EF</color>
|
||||
<color name="md_theme_surfaceContainer_highContrast">#DEE4E0</color>
|
||||
<color name="md_theme_surfaceContainerHigh_highContrast">#CFD6D2</color>
|
||||
<color name="md_theme_surfaceContainerHighest_highContrast">#C1C8C5</color>
|
||||
|
||||
<color name="teal">#338574</color> <!-- Primary color (light mode) -->
|
||||
<color name="teal_light">#65b5a3</color> <!-- Primary color (dark mode) -->
|
||||
<color name="teal_dark">#2a6e60</color> <!-- Action bar background in action mode (light mode) -->
|
||||
<color name="red_light">#fe4d2e</color> <!-- Danger text (dark mode) -->
|
||||
<color name="red_dark">#c30000</color> <!-- Danger text (light mode) -->
|
||||
<color name="action_bar">#338574</color> <!-- md_theme_primary (light) -->
|
||||
<color name="detail_activity_background">#EEEEEE</color> <!-- Light gray for detail activity in light mode -->
|
||||
|
||||
<!-- Remove black status bar in Action mode: https://stackoverflow.com/a/79456725 -->
|
||||
<color name="abc_decor_view_status_guard" tools:override="true">@android:color/transparent</color>
|
||||
<color name="abc_decor_view_status_guard_light" tools:override="true">@android:color/transparent</color>
|
||||
</resources>
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
<string name="main_menu_report_bug_title">Report a bug</string>
|
||||
<string name="main_menu_docs_title">Read the docs</string>
|
||||
<string name="main_menu_rate_title">Rate the app ⭐</string>
|
||||
<string name="main_menu_donate_title">Donate 💸</string>
|
||||
|
||||
<!-- Main activity: Action mode -->
|
||||
<string name="main_action_mode_menu_unsubscribe">Unsubscribe</string>
|
||||
|
|
@ -310,6 +309,9 @@
|
|||
<string name="settings_general_dark_mode_entry_system">Use system default</string>
|
||||
<string name="settings_general_dark_mode_entry_light">Light mode</string>
|
||||
<string name="settings_general_dark_mode_entry_dark">Dark mode</string>
|
||||
<string name="settings_general_dynamic_colors_title">Dynamic colors</string>
|
||||
<string name="settings_general_dynamic_colors_summary_enabled">Using the dynamic system colors</string>
|
||||
<string name="settings_general_dynamic_colors_summary_disabled">Using the ntfy theme colors</string>
|
||||
<string name="settings_backup_restore_header">Backup & Restore</string>
|
||||
<string name="settings_backup_restore_backup_title">Back up to file</string>
|
||||
<string name="settings_backup_restore_backup_summary">Export config, notifications, and users</string>
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Main app theme; dark theme styles see values-night/styles.xml -->
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/teal</item>
|
||||
<item name="colorAccent">@color/teal</item> <!-- checkboxes, text fields -->
|
||||
<item name="android:colorBackground">@color/white</item> <!-- background -->
|
||||
<item name="android:statusBarColor">@color/teal</item>
|
||||
<item name="actionModeBackground">@color/teal_dark</item>
|
||||
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
|
||||
</style>
|
||||
|
||||
<style name="DangerText" parent="@android:style/TextAppearance">
|
||||
<item name="android:textColor">@color/red_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="FloatingActionButton" parent="@style/Widget.MaterialComponents.FloatingActionButton">
|
||||
<item name="tint">@color/white</item>
|
||||
<item name="backgroundTint">@color/teal</item>
|
||||
</style>
|
||||
|
||||
<style name="CardView" parent="@style/Widget.MaterialComponents.CardView">
|
||||
<item name="cardBackgroundColor">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="CardViewBackground">
|
||||
<item name="android:background">@color/gray_400</item>
|
||||
</style>
|
||||
|
||||
<!-- Rounded corners in images, see https://stackoverflow.com/a/61960983/1440785 -->
|
||||
<style name="roundedCornersImageView" parent="">
|
||||
<item name="cornerFamily">rounded</item>
|
||||
<item name="cornerSize">5dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
122
app/src/main/res/values/themes.xml
Normal file
122
app/src/main/res/values/themes.xml
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/md_theme_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_error</item>
|
||||
<item name="colorOnError">@color/md_theme_onError</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_errorContainer</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_outline</item>
|
||||
<item name="colorOutlineVariant">@color/md_theme_outlineVariant</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item>
|
||||
<item name="colorPrimaryFixed">@color/md_theme_primaryFixed</item>
|
||||
<item name="colorOnPrimaryFixed">@color/md_theme_onPrimaryFixed</item>
|
||||
<item name="colorPrimaryFixedDim">@color/md_theme_primaryFixedDim</item>
|
||||
<item name="colorOnPrimaryFixedVariant">@color/md_theme_onPrimaryFixedVariant</item>
|
||||
<item name="colorSecondaryFixed">@color/md_theme_secondaryFixed</item>
|
||||
<item name="colorOnSecondaryFixed">@color/md_theme_onSecondaryFixed</item>
|
||||
<item name="colorSecondaryFixedDim">@color/md_theme_secondaryFixedDim</item>
|
||||
<item name="colorOnSecondaryFixedVariant">@color/md_theme_onSecondaryFixedVariant</item>
|
||||
<item name="colorTertiaryFixed">@color/md_theme_tertiaryFixed</item>
|
||||
<item name="colorOnTertiaryFixed">@color/md_theme_onTertiaryFixed</item>
|
||||
<item name="colorTertiaryFixedDim">@color/md_theme_tertiaryFixedDim</item>
|
||||
<item name="colorOnTertiaryFixedVariant">@color/md_theme_onTertiaryFixedVariant</item>
|
||||
<item name="colorSurfaceDim">@color/md_theme_surfaceDim</item>
|
||||
<item name="colorSurfaceBright">@color/md_theme_surfaceBright</item>
|
||||
<item name="colorSurfaceContainerLowest">@color/md_theme_surfaceContainerLowest</item>
|
||||
<item name="colorSurfaceContainerLow">@color/md_theme_surfaceContainerLow</item>
|
||||
<item name="colorSurfaceContainer">@color/md_theme_surfaceContainer</item>
|
||||
<item name="colorSurfaceContainerHigh">@color/md_theme_surfaceContainerHigh</item>
|
||||
<item name="colorSurfaceContainerHighest">@color/md_theme_surfaceContainerHighest</item>
|
||||
|
||||
<item name="switchPreferenceCompatStyle">@style/MaterialSwitch</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
|
||||
<item name="actionModeStyle">@style/ActionMode</item>
|
||||
<item name="actionModeCloseButtonStyle">@style/ActionModeCloseButtonStyle</item>
|
||||
<item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="OverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow" />
|
||||
|
||||
<style name="DangerText" parent="@android:style/TextAppearance">
|
||||
<item name="android:textColor">?attr/colorError</item>
|
||||
</style>
|
||||
|
||||
<style name="FloatingActionButton" parent="@style/Widget.Material3.FloatingActionButton.Primary">
|
||||
<item name="backgroundTint">?attr/colorPrimary</item>
|
||||
<item name="tint">?attr/colorOnPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="CardView" parent="@style/Widget.Material3.CardView.Elevated" />
|
||||
|
||||
<style name="CardViewBackground" />
|
||||
|
||||
<!-- Rounded corners in images, see https://stackoverflow.com/a/61960983/1440785 -->
|
||||
<style name="roundedCornersImageView" parent="">
|
||||
<item name="cornerFamily">rounded</item>
|
||||
<item name="cornerSize">5dp</item>
|
||||
</style>
|
||||
|
||||
<!-- Material Design 3 switches in the preferences -->
|
||||
<style name="MaterialSwitch" parent="@style/Preference.SwitchPreferenceCompat.Material">
|
||||
<item name="widgetLayout">@layout/view_preference_switch</item>
|
||||
</style>
|
||||
|
||||
<!-- Action mode colors -->
|
||||
<style name="ActionMode" parent="@style/Widget.AppCompat.ActionMode">
|
||||
<item name="background">?attr/colorPrimary</item>
|
||||
<item name="titleTextStyle">@style/ActionModeTitle</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionModeTitle" parent="@style/TextAppearance.AppCompat.Widget.ActionMode.Title">
|
||||
<item name="android:textColor">?attr/colorOnPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionModeCloseButtonStyle" parent="Widget.AppCompat.ActionButton.CloseMode">
|
||||
<item name="android:tint">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<!-- Banner style with reduced corner radius -->
|
||||
<style name="BannerCardStyle" parent="Widget.Material3.CardView.Elevated">
|
||||
<item name="shapeAppearanceOverlay">@style/BannerShapeAppearance</item>
|
||||
</style>
|
||||
|
||||
<style name="BannerShapeAppearance">
|
||||
<item name="cornerFamily">rounded</item>
|
||||
<item name="cornerSize">8dp</item>
|
||||
</style>
|
||||
|
||||
<!-- Full-screen dialog style for Material 3 compliance -->
|
||||
<style name="Theme.App.FullScreenDialog" parent="AppTheme">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:statusBarColor">?attr/colorSurface</item>
|
||||
<item name="android:windowBackground">?attr/colorSurface</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation.App.FullScreenDialog</item>
|
||||
</style>
|
||||
|
||||
<!-- Slide animation for full-screen dialog -->
|
||||
<style name="Animation.App.FullScreenDialog" parent="Animation.AppCompat.Dialog">
|
||||
<item name="android:windowEnterAnimation">@anim/slide_in_bottom</item>
|
||||
<item name="android:windowExitAnimation">@anim/slide_out_bottom</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
<string name="settings_general_default_base_url_key" translatable="false">DefaultBaseURL</string>
|
||||
<string name="settings_general_users_key" translatable="false">ManageUsers</string>
|
||||
<string name="settings_general_dark_mode_key" translatable="false">DarkMode</string>
|
||||
<string name="settings_general_dynamic_colors_key" translatable="false">DynamicColors</string>
|
||||
<string name="settings_backup_restore_backup_key" translatable="false">Backup</string>
|
||||
<string name="settings_backup_restore_restore_key" translatable="false">Restore</string>
|
||||
<string name="settings_advanced_broadcast_key" translatable="false">BroadcastEnabled</string>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<PreferenceCategory
|
||||
app:key="@string/detail_settings_notifications_header_key"
|
||||
app:title="@string/settings_notifications_header">
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/detail_settings_notifications_instant_key"
|
||||
app:title="@string/detail_settings_notifications_instant_title"
|
||||
app:isPreferenceVisible="false"/>
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
app:entryValues="@array/detail_settings_notifications_insistent_max_priority_values"
|
||||
app:defaultValue="-1"
|
||||
app:isPreferenceVisible="false"/> <!-- Same as Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL -->
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/detail_settings_notifications_dedicated_channels_key"
|
||||
app:title="@string/detail_settings_notifications_dedicated_channels_title"
|
||||
app:isPreferenceVisible="false"/>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
app:entries="@array/settings_notifications_auto_delete_entries"
|
||||
app:entryValues="@array/settings_notifications_auto_delete_values"
|
||||
app:defaultValue="2592000"/>
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/settings_notifications_insistent_max_priority_key"
|
||||
app:title="@string/settings_notifications_insistent_max_priority_title"
|
||||
app:defaultValue="false"/>
|
||||
|
|
@ -37,9 +37,7 @@
|
|||
<PreferenceCategory app:title="@string/settings_general_header">
|
||||
<EditTextPreference
|
||||
app:key="@string/settings_general_default_base_url_key"
|
||||
app:title="@string/settings_general_default_base_url_title"
|
||||
app:dialogLayout="@layout/preference_dialog_edittext_edited"
|
||||
app:dialogMessage="@string/settings_general_default_base_url_message"/>
|
||||
app:title="@string/settings_general_default_base_url_title" />
|
||||
<Preference
|
||||
app:key="@string/settings_general_users_key"
|
||||
app:title="@string/settings_general_users_title"
|
||||
|
|
@ -51,6 +49,10 @@
|
|||
app:entries="@array/settings_general_dark_mode_entries"
|
||||
app:entryValues="@array/settings_general_dark_mode_values"
|
||||
app:defaultValue="-1"/>
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/settings_general_dynamic_colors_key"
|
||||
app:title="@string/settings_general_dynamic_colors_title"
|
||||
app:isPreferenceVisible="false"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory app:title="@string/settings_backup_restore_header">
|
||||
<ListPreference
|
||||
|
|
@ -75,15 +77,15 @@
|
|||
<Preference
|
||||
app:key="@string/settings_advanced_exact_alarms_key"
|
||||
app:title="@string/settings_advanced_exact_alarms_title"/>
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/settings_advanced_broadcast_key"
|
||||
app:title="@string/settings_advanced_broadcast_title"
|
||||
app:enabled="true"/>
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/settings_advanced_unifiedpush_key"
|
||||
app:title="@string/settings_advanced_unifiedpush_title"
|
||||
app:enabled="true"/>
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
app:key="@string/settings_advanced_record_logs_key"
|
||||
app:title="@string/settings_advanced_record_logs_title"
|
||||
app:enabled="true"/>
|
||||
|
|
|
|||
9
fastlane/metadata/android/en-US/changelog/46.txt
Normal file
9
fastlane/metadata/android/en-US/changelog/46.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
This release makes changes to comply with the Google Play policies.
|
||||
See https://github.com/binwiederhier/ntfy/issues/1463 for details.
|
||||
|
||||
Changes:
|
||||
- Remove the "Donate" button from menu (all variants)
|
||||
- Change default display name from "ntfy.sh/mytopic" to "mytopic" (all variants)
|
||||
- Remove links to ntfy docs and issue tracker (Play variant only)
|
||||
- Remove how-to links to ntfy.sh in a few places (Play variant only)
|
||||
- Remove "Copy topic address" from subscription menu (Play variant only)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
Features:
|
||||
* Added GIF support for preview images (ntfy-android#76, thanks to @MichaelArkh)
|
||||
* Added WebP support for preview images (ntfy-android#81, thanks to @jokakilla)
|
||||
* Added UnifiedPush distributor selection support (ntfy-android#137, thanks to @p1gp1g)
|
||||
|
||||
Bug fixes + maintenance:
|
||||
* Remove REQUEST_INSTALL_PACKAGES permission (#684)
|
||||
2
fastlane/metadata/android/en-US/changelog/48.txt
Normal file
2
fastlane/metadata/android/en-US/changelog/48.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Features:
|
||||
* Moved the user interface to Material 3 and added dynamic color support (#580, ntfy-android#56, ntfy-android#126, ntfy-android#135, thanks to @Bnyro and @cyb3rko for the implementation, and to @RokeJulianLockhart for reporting)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue