Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/src/main/java/io/heckel/ntfy/db/Repository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,22 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
return sharedPrefs.getString(SHARED_PREFS_CONNECTION_PROTOCOL, null) ?: CONNECTION_PROTOCOL_JSONHTTP
}

fun setDateTimeFormat(dateTimeFormat: String) {
if (dateTimeFormat == DATETIME_FORMAT_LOCALE) {
sharedPrefs.edit {
remove(SHARED_PREFS_DATETIME_FORMAT)
}
} else {
sharedPrefs.edit {
putString(SHARED_PREFS_DATETIME_FORMAT, dateTimeFormat)
}
}
}

fun getDateTimeFormat(): String {
return sharedPrefs.getString(SHARED_PREFS_DATETIME_FORMAT, DATETIME_FORMAT_LOCALE) ?: DATETIME_FORMAT_LOCALE
}

fun getBroadcastEnabled(): Boolean {
return sharedPrefs.getBoolean(SHARED_PREFS_BROADCAST_ENABLED, true) // Enabled by default
}
Expand Down Expand Up @@ -611,6 +627,7 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val SHARED_PREFS_AUTO_DOWNLOAD_MAX_SIZE = "AutoDownload"
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
const val SHARED_PREFS_DATETIME_FORMAT = "DateTimeFormat"
const val SHARED_PREFS_DARK_MODE = "DarkMode"
const val SHARED_PREFS_DYNAMIC_COLORS = "DynamicColors"
const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled"
Expand Down Expand Up @@ -655,6 +672,9 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val CONNECTION_PROTOCOL_JSONHTTP = "jsonhttp"
const val CONNECTION_PROTOCOL_WS = "ws"

const val DATETIME_FORMAT_LOCALE = "locale"
const val DATETIME_FORMAT_ISO8601 = "iso8601"

const val BATTERY_OPTIMIZATIONS_REMIND_TIME_ALWAYS = 1L
const val BATTERY_OPTIMIZATIONS_REMIND_TIME_NEVER = Long.MAX_VALUE

Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
0L -> Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show()
1L -> Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show()
else -> {
val formattedDate = formatDateShort(mutedUntilTimestamp)
val formattedDate = formatDateShort(this@DetailActivity, mutedUntilTimestamp)
Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_muted_until_toast_message, formattedDate), Toast.LENGTH_LONG).show()
}
}
Expand Down Expand Up @@ -843,7 +843,7 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
notificationsDisabledForeverItem?.isVisible = subscriptionMutedUntil == 1L
notificationsDisabledUntilItem?.isVisible = subscriptionMutedUntil > 1L
if (subscriptionMutedUntil > 1L) {
val formattedDate = formatDateShort(subscriptionMutedUntil)
val formattedDate = formatDateShort(this, subscriptionMutedUntil)
notificationsDisabledUntilItem?.title = getString(R.string.detail_menu_notifications_disabled_until, formattedDate)
}
}
Expand Down Expand Up @@ -975,7 +975,7 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
val content = adapter.selected.joinToString("\n\n") { notificationId ->
val notification = repository.getNotification(notificationId)
notification?.let {
decodeMessage(it) + "\n" + Date(it.timestamp * 1000).toString()
decodeMessage(it) + "\n" + formatDateShort(this@DetailActivity, it.timestamp)
}.orEmpty()
}
runOnUiThread {
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
val unmatchedTags = unmatchedTags(splitTags(notification.tags))
val message = maybeAppendActionErrors(formatMessage(notification), notification)

dateView.text = formatDateShort(notification.timestamp)
dateView.text = formatDateShort(context, notification.timestamp)
if (notification.isMarkdown()) {
messageView.autoLinkMask = 0
markwon.setMarkdown(messageView, message.toString())
Expand Down Expand Up @@ -353,7 +353,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
if (expired) {
infos.add(context.getString(R.string.detail_item_download_info_not_downloaded_expired))
} else if (expires) {
infos.add(context.getString(R.string.detail_item_download_info_not_downloaded_expires_x, formatDateShort(attachment.expires)))
infos.add(context.getString(R.string.detail_item_download_info_not_downloaded_expires_x, formatDateShort(context, attachment.expires)))
} else {
infos.add(context.getString(R.string.detail_item_download_info_not_downloaded))
}
Expand All @@ -363,15 +363,15 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
if (expired) {
infos.add(context.getString(R.string.detail_item_download_info_deleted_expired))
} else if (expires) {
infos.add(context.getString(R.string.detail_item_download_info_deleted_expires_x, formatDateShort(attachment.expires)))
infos.add(context.getString(R.string.detail_item_download_info_deleted_expires_x, formatDateShort(context, attachment.expires)))
} else {
infos.add(context.getString(R.string.detail_item_download_info_deleted))
}
} else if (failed) {
if (expired) {
infos.add(context.getString(R.string.detail_item_download_info_download_failed_expired))
} else if (expires) {
infos.add(context.getString(R.string.detail_item_download_info_download_failed_expires_x, formatDateShort(attachment.expires)))
infos.add(context.getString(R.string.detail_item_download_info_download_failed_expires_x, formatDateShort(context, attachment.expires)))
} else {
infos.add(context.getString(R.string.detail_item_download_info_download_failed))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class DetailSettingsActivity : AppCompatActivity() {
Repository.MUTED_UNTIL_SHOW_ALL -> getString(R.string.settings_notifications_muted_until_show_all)
Repository.MUTED_UNTIL_FOREVER -> getString(R.string.settings_notifications_muted_until_forever)
else -> {
val formattedDate = formatDateShort(mutedUntilValue)
val formattedDate = formatDateShort(requireContext(), mutedUntilValue)
getString(R.string.settings_notifications_muted_until_x, formattedDate)
}
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific
notificationsDisabledForeverItem?.isVisible = mutedUntilSeconds == 1L
notificationsDisabledUntilItem?.isVisible = mutedUntilSeconds > 1L
if (mutedUntilSeconds > 1L) {
val formattedDate = formatDateShort(mutedUntilSeconds)
val formattedDate = formatDateShort(this@MainActivity, mutedUntilSeconds)
notificationsDisabledUntilItem?.title = getString(R.string.main_menu_notifications_disabled_until, formattedDate)
}
}
Expand Down Expand Up @@ -645,7 +645,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific
0L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show()
1L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show()
else -> {
val formattedDate = formatDateShort(mutedUntilTimestamp)
val formattedDate = formatDateShort(this, mutedUntilTimestamp)
Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_until_toast_message, formattedDate), Toast.LENGTH_LONG).show()
}
}
Expand Down
11 changes: 5 additions & 6 deletions app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.util.displayName
import io.heckel.ntfy.util.formatDate
import io.heckel.ntfy.util.formatTime
import io.heckel.ntfy.util.readBitmapFromUriOrNull
import java.text.DateFormat
import java.util.*

class MainAdapter(
private val repository: Repository,
Expand Down Expand Up @@ -95,14 +95,13 @@ class MainAdapter(
if (subscription.instant && subscription.connectionDetails.state == ConnectionState.CONNECTING) {
statusMessage += ", " + context.getString(R.string.main_item_status_reconnecting)
}
val date = Date(subscription.lastActive * 1000)
val dateStr = DateFormat.getDateInstance(DateFormat.SHORT).format(date)
val dateStr = formatDate(context, subscription.lastActive)
val moreThanOneDay = System.currentTimeMillis()/1000 - subscription.lastActive > 24 * 60 * 60
val sameDay = dateStr == DateFormat.getDateInstance(DateFormat.SHORT).format(Date()) // Omg this is horrible
val sameDay = dateStr == formatDate(context, System.currentTimeMillis() / 1000)
val dateText = if (subscription.lastActive == 0L) {
""
} else if (sameDay) {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
formatTime(context, subscription.lastActive)
} else if (!moreThanOneDay) {
context.getString(R.string.main_item_date_yesterday)
} else {
Expand Down
22 changes: 21 additions & 1 deletion app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
Repository.MUTED_UNTIL_SHOW_ALL -> getString(R.string.settings_notifications_muted_until_show_all)
Repository.MUTED_UNTIL_FOREVER -> getString(R.string.settings_notifications_muted_until_forever)
else -> {
val formattedDate = formatDateShort(mutedUntilValue)
val formattedDate = formatDateShort(requireContext(), mutedUntilValue)
getString(R.string.settings_notifications_muted_until_x, formattedDate)
}
}
Expand Down Expand Up @@ -351,6 +351,26 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}

val dateTimeFormatPrefId = context?.getString(R.string.settings_general_datetime_format_key) ?: return
val dateTimeFormat: ListPreference? = findPreference(dateTimeFormatPrefId)
dateTimeFormat?.value = repository.getDateTimeFormat()
dateTimeFormat?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val dateTimeFormatValue = value ?: repository.getDateTimeFormat()
repository.setDateTimeFormat(dateTimeFormatValue)
}

override fun getString(key: String?, defValue: String?): String {
return repository.getDateTimeFormat()
}
}
dateTimeFormat?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
when (pref.value) {
Repository.DATETIME_FORMAT_ISO8601 -> getString(R.string.settings_general_datetime_format_summary_iso8601)
else -> getString(R.string.settings_general_datetime_format_summary_locale)
}
}

// Language
val languagePrefId = context?.getString(R.string.settings_general_language_key) ?: return
val language: ListPreference? = findPreference(languagePrefId)
Expand Down
40 changes: 38 additions & 2 deletions app/src/main/java/io/heckel/ntfy/util/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ import java.io.IOException
import java.security.MessageDigest
import java.security.SecureRandom
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.text.StringCharacterIterator
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import kotlin.math.abs
import kotlin.math.absoluteValue
import androidx.core.net.toUri
Expand Down Expand Up @@ -130,8 +133,41 @@ fun normalizeBaseUrl(url: String): String {
}

fun formatDateShort(timestampSecs: Long): String {
val date = Date(timestampSecs*1000)
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date)
return formatDateTime(Date(timestampSecs * 1000), Repository.DATETIME_FORMAT_LOCALE)
}

fun formatDateShort(context: Context, timestampSecs: Long): String {
val repository = Repository.getInstance(context)
return formatDateTime(Date(timestampSecs * 1000), repository.getDateTimeFormat())
}

fun formatDate(context: Context, timestampSecs: Long): String {
val repository = Repository.getInstance(context)
val date = Date(timestampSecs * 1000)
return if (repository.getDateTimeFormat() == Repository.DATETIME_FORMAT_ISO8601) {
SimpleDateFormat("yyyy-MM-dd", Locale.US).format(date)
} else {
DateFormat.getDateInstance(DateFormat.SHORT).format(date)
}
}

fun formatTime(context: Context, timestampSecs: Long): String {
val repository = Repository.getInstance(context)
val date = Date(timestampSecs * 1000)
return if (repository.getDateTimeFormat() == Repository.DATETIME_FORMAT_ISO8601) {
SimpleDateFormat("HH:mm", Locale.US).format(date)
} else {
DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
}
}

private fun formatDateTime(date: Date, dateTimeFormat: String): String {
return if (dateTimeFormat == Repository.DATETIME_FORMAT_ISO8601) {
SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
.format(date)
} else {
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date)
}
}

fun toPriority(priority: Int?): Int {
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@
<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_datetime_format_title">Date/time format</string>
<string name="settings_general_datetime_format_summary_locale">Using locale default date/time format</string>
<string name="settings_general_datetime_format_summary_iso8601">Using ISO 8601 date/time format</string>
<string name="settings_general_datetime_format_entry_locale">Locale default</string>
<string name="settings_general_datetime_format_entry_iso8601">ISO 8601</string>
<string name="settings_general_language_title">Language</string>
<string name="settings_general_language_summary_system">Using system default</string>
<string name="settings_general_language_system_default">System default</string>
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/values/values.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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_datetime_format_key" translatable="false">DateTimeFormat</string>
<string name="settings_general_language_key" translatable="false">Language</string>
<string name="settings_general_dynamic_colors_key" translatable="false">DynamicColors</string>
<string name="settings_general_message_bar_key" translatable="false">MessageBarEnabled</string>
Expand Down Expand Up @@ -208,4 +209,12 @@
<item>1</item>
<item>2</item>
</string-array>
<string-array name="settings_general_datetime_format_entries">
<item>@string/settings_general_datetime_format_entry_locale</item>
<item>@string/settings_general_datetime_format_entry_iso8601</item>
</string-array>
<string-array name="settings_general_datetime_format_values">
<item>locale</item>
<item>iso8601</item>
</string-array>
</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/xml/main_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
app:entries="@array/settings_general_dark_mode_entries"
app:entryValues="@array/settings_general_dark_mode_values"
app:defaultValue="-1"/>
<ListPreference
app:key="@string/settings_general_datetime_format_key"
app:title="@string/settings_general_datetime_format_title"
app:entries="@array/settings_general_datetime_format_entries"
app:entryValues="@array/settings_general_datetime_format_values"
app:defaultValue="locale"/>
<SwitchPreferenceCompat
app:key="@string/settings_general_dynamic_colors_key"
app:title="@string/settings_general_dynamic_colors_title"
Expand Down