From e543428ed53fc629fe0b614ab1c600f0d3757f60 Mon Sep 17 00:00:00 2001 From: alansley Date: Thu, 29 Aug 2024 17:32:29 +1000 Subject: [PATCH 1/5] WIP --- .../components/SwitchPreferenceCompat.kt | 2 - .../CorrectedPreferenceFragment.java | 5 +- .../thoughtcrime/securesms/util/DateUtils.kt | 105 ++++++++++++++++-- .../utilities/TextSecurePreferences.kt | 46 +++++++- 4 files changed, 141 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SwitchPreferenceCompat.kt b/app/src/main/java/org/thoughtcrime/securesms/components/SwitchPreferenceCompat.kt index 9161dd828d..0b4a04a69f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/SwitchPreferenceCompat.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SwitchPreferenceCompat.kt @@ -3,11 +3,9 @@ package org.thoughtcrime.securesms.components import android.content.Context import android.util.AttributeSet import androidx.preference.CheckBoxPreference -import com.squareup.phrase.Phrase import network.loki.messenger.R import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY import org.thoughtcrime.securesms.ui.getSubbedCharSequence -import org.thoughtcrime.securesms.ui.getSubbedString class SwitchPreferenceCompat : CheckBoxPreference { private var listener: OnPreferenceClickListener? = null diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java index d626b9ce5f..489ef4b589 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.preferences; - import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Typeface; @@ -9,11 +8,9 @@ import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; -import androidx.fragment.app.DialogFragment; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceFragmentCompat; @@ -21,8 +18,8 @@ import androidx.preference.PreferenceGroupAdapter; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceViewHolder; import androidx.recyclerview.widget.RecyclerView; -import org.thoughtcrime.securesms.conversation.v2.ViewUtil; import network.loki.messenger.R; +import org.thoughtcrime.securesms.conversation.v2.ViewUtil; public abstract class CorrectedPreferenceFragment extends PreferenceFragmentCompat { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt index 10d2fceb79..2d200784f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt @@ -20,10 +20,8 @@ import android.annotation.SuppressLint import android.content.Context import android.os.Build import android.text.format.DateFormat -import androidx.compose.ui.text.capitalize +import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.Log -import java.text.DateFormat.SHORT -import java.text.DateFormat.getTimeInstance import java.text.ParseException import java.text.SimpleDateFormat import java.util.Calendar @@ -44,6 +42,14 @@ object DateUtils : android.text.format.DateUtils() { private val DAY_PRECISION_DATE_FORMAT = SimpleDateFormat("yyyyMMdd") private val HOUR_PRECISION_DATE_FORMAT = SimpleDateFormat("yyyyMMddHH") + // Preferred date and time formats for the user - these are stored in the user's preferences. + // We set them as invalid on startup (range is 0..8 and 0..2 respectively) so we only have to + // retrieve the preference once rather than every time we wish to format a date or time. + // See: TextSecurePreferences.DATE_FORMAT_PREF and TextSecurePreferences for further details. + private var userPreferredDateFormat: Int = -1 + private var userPreferredTimeFormat: Int = 2//-1 + + private fun isWithin(millis: Long, span: Long, unit: TimeUnit): Boolean { return System.currentTimeMillis() - millis <= unit.toMillis(span) } @@ -82,27 +88,110 @@ object DateUtils : android.text.format.DateUtils() { FORMAT_SHOW_DATE).toString() } + // THIS IS THE METHOD THAT ACTUALLY GETS USED TO GET THE DATE TIME fun getFormattedDateTime(time: Long, template: String, locale: Locale): String { val localizedPattern = getLocalizedPattern(template, locale) return SimpleDateFormat(localizedPattern, locale).format(Date(time)) } - fun getHourFormat(c: Context?): String { - return if ((DateFormat.is24HourFormat(c))) "HH:mm" else "hh:mm a" + // Method to get the user's preferred time format, whether that's 12-hour or 24-hour + fun getHourFormat(c: Context): String { + // If this is the first run.. + if (userPreferredTimeFormat == -1) { + // ..update our preferred time format (will return -1 if no saved pref). + userPreferredTimeFormat = TextSecurePreferences.getTimeFormatPref(c) + + // If no saved value was written we'll write 0 for "Follow system setting" - this will only run on first install + if (userPreferredTimeFormat == -1) { + userPreferredTimeFormat = 0 + TextSecurePreferences.setTimeFormatPref(c, userPreferredTimeFormat) + } + + // If the preferred time format is "Follow system setting" then we need to find out what the system setting is! + if (userPreferredTimeFormat == 0) { + val is24HourFormat = DateFormat.is24HourFormat(c) + + // Set the time format we'll use to either 24 or 12 hours. + // IMPORTANT: We don't WRITE this to the pref - we just use it while the app is running! + // Note: See TextSecurePreferences.TIME_FORMAT_PREF for further details of available formats. + userPreferredTimeFormat = if (is24HourFormat) 2 else 1 + } + } + + // At this point userPreferredTimeFormat will ALWAYS be either 1 or 2 - regardless of if the saved + // pref is 0 to "Follow system settings". + return if (userPreferredTimeFormat == 1) "hh:mm a" else "HH:mm" } fun getDisplayFormattedTimeSpanString(c: Context, locale: Locale, timestamp: Long): String { - // If the timestamp is within the last 24 hours we just give the time, e.g, "1:23 PM" or - // "13:23" depending on 12/24 hour formatting. - return if (isToday(timestamp)) { + // Note: Date-formats are in TR-35 format. + // See: https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns + val t = if (isToday(timestamp)) { + Log.w("ACL", "Within today") + // If it's within the last 24 hours we just give the time in 24-hour format, such as "13:27" for 1:27pm getFormattedDateTime(timestamp, getHourFormat(c), locale) } else if (isWithin(timestamp, 6, TimeUnit.DAYS)) { + Log.w("ACL", "Within week") + // If it's within the last week we give the day as 3 letters then the time in 24-hour format, such as "Fri 13:27" for Friday 1:27pm getFormattedDateTime(timestamp, "EEE " + getHourFormat(c), locale) } else if (isWithin(timestamp, 365, TimeUnit.DAYS)) { + Log.w("ACL", "Within year") + // If it's within the last year we give the month as 3 letters then the time in 24-hour format, such as "Mar 13:27" for March 1:27pm + // CAREFUL: "MMM d + getHourFormat(c)" actually turns out to be "8 July, 17:14" etc. - it is DAY-NUMBER and then MONTH (which can go up to 4 chars) - and THEN the time. Wild. getFormattedDateTime(timestamp, "MMM d " + getHourFormat(c), locale) } else { + // NOTE: The `userPreferredDateFormat` is ONLY ever used on dates which exceed one year! + // See the Figma linked in SES-360 for details. + + + Log.w("ACL", "More than 1 year") + // If the date is more than a year ago then we get "19 July 2023, 16:19" type format + + // If this is the first run.. + if (userPreferredDateFormat == -1) { + // ..update our preferred date format (will return -1 if no saved pref). + userPreferredDateFormat = TextSecurePreferences.getDateFormatPref(c) + + // If no saved value was written we'll write 0 for "Follow system setting" - this will only run on first install + if (userPreferredDateFormat == -1) { + userPreferredDateFormat = 0 + //TextSecurePreferences.setDateFormatPref(c, userPreferredDateFormat) ACL PUT THIS BACK!!!!!!!!!!!!!!!!!!!!! + } + + // If the preferred date format is "Follow system setting" then we need to find out what the system setting is! + if (userPreferredDateFormat == 0) { + val dateFormat = DateFormat.getDateFormat(c) + + // Check if the DateFormat instance is a SimpleDateFormat + if (dateFormat is SimpleDateFormat) { + Log.w("ACL", "Date pattern: " + dateFormat.toPattern()) + + when (dateFormat) { + "M/d/yy" -> FFS + } + + + } else { + // If the dateFormat isn't a SimpleDateFormat from which we can extract a pattern then the best + // we can do is pick a sensible default like DD/MM/YYYY - which equates to option 3 out of our + // available options (see TextSecurePreferences.DATE_FORMAT_PREF for further details). + userPreferredDateFormat = 3 + // IMPORTANT: We don't WRITE this to the pref - we just use it while the app is running! + } + + // Set the time format we'll use to either 24 or 12 hours. + // IMPORTANT: We don't WRITE this to the pref - we just use it while the app is running! + // Note: See TextSecurePreferences.TIME_FORMAT_PREF for further details of available formats. + //userPreferredTimeFormat = if (is24HourFormat) 2 else 1 + } + } + getFormattedDateTime(timestamp, "MMM d " + getHourFormat(c) + ", yyyy", locale) } + + Log.w("ACL", "t is: $t") + return t + } fun getDetailedDateFormatter(context: Context?, locale: Locale): SimpleDateFormat { diff --git a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index 4c974e7d60..842b234a5b 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -310,6 +310,26 @@ interface TextSecurePreferences { // for the lifetime of the Session installation. const val HAVE_WARNED_USER_ABOUT_SAVING_ATTACHMENTS = "libsession.HAVE_WARNED_USER_ABOUT_SAVING_ATTACHMENTS" + // Key name for the user's preferred date format as an Int. See ticket SES-360 for further details & Figma design. + // Values for various formats are as follows: + // 0 - Follow system settings (default) + // 1 - M/D/YY - example: 1/2/24 (which is 2nd Jan 2024), or 12/25/24 (which is 25th Dec 2024) + // 2 - D/M/YY - example: 2/1/24 (which is 2nd Jan 2024), or 25/12/24 (which is 25th Dec 2024) + // 3 - DD/MM/YYYY - example: 02/01/2024 (which is 2nd Jan 2024), or 25/12/2024 (which is 25th Dec 2024) + // 4 - DD.MM.YYYY - example: 02.01.2024 (which is 2nd Jan 2024), or 25.12.2024 (which is 25th Dec 2024) + // 5 - DD-MM-YYYY - example: 02-01-2024 (which is 2nd Jan 2024), or 25-12-2024 (which is 25th Dec 2024) + // 6 - YYYY/M/D - example: 2024/1/2 (which is 2nd Jan 2024), or 2024/12/25 (which is 25th Dec 2024) + // 7 - YYYY.M.D - example: 2024.1.2 (which is 2nd Jan 2024), or 2024.12.25 (which is 25th Dec 2024) + // 8 - YYYY-M-D - example: 2024-1-2 (which is 2nd Jan 2024), or 2024-12-25 (which is 25th Dec 2024) + const val DATE_FORMAT_PREF = "libsession.DATE_FORMAT_PREF" + + // Key name for the user's preferred time format as an Int + // Values for various formats are as follows: + // 0 - Follow system settings (default) + // 1 - 12h - example: 3:45 PM + // 2 - 24h - example: 15:45 + const val TIME_FORMAT_PREF = "libsession.TIME_FORMAT_PREF" + @JvmStatic fun getLastConfigurationSyncTime(context: Context): Long { return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0) @@ -990,8 +1010,14 @@ interface TextSecurePreferences { setBooleanPreference(context, FINGERPRINT_KEY_GENERATED, true) } + @JvmStatic + fun clearAll(context: Context) { + getDefaultSharedPreferences(context).edit().clear().commit() + } + // ----- Get / set methods for if we have already warned the user that saving attachments will allow other apps to access them ----- + // Note: We only ever show the warning dialog about this ONCE - when the user accepts this fact we write true to the flag & never show again. @JvmStatic fun getHaveWarnedUserAboutSavingAttachments(context: Context): Boolean { return getBooleanPreference(context, HAVE_WARNED_USER_ABOUT_SAVING_ATTACHMENTS, false) @@ -1001,12 +1027,26 @@ interface TextSecurePreferences { fun setHaveWarnedUserAboutSavingAttachments(context: Context) { setBooleanPreference(context, HAVE_WARNED_USER_ABOUT_SAVING_ATTACHMENTS, true) } - // --------------------------------------------------------------------------------------------------------------------------------- + // ----- Get / set methods for the user's date format preference ----- @JvmStatic - fun clearAll(context: Context) { - getDefaultSharedPreferences(context).edit().clear().commit() + fun getDateFormatPref(context: Context): Int { + // Note: 0 means "follow system setting" (default) - go to the declaration of DATE_FORMAT_PREF for further details. + return getIntegerPreference(context, DATE_FORMAT_PREF, -1) } + + @JvmStatic + fun setDateFormatPref(context: Context, value: Int) { setIntegerPreference(context, DATE_FORMAT_PREF, value) } + + // ----- Get / set methods for the user's time format preference ----- + @JvmStatic + fun getTimeFormatPref(context: Context): Int { + // Note: 0 means "follow system setting" (default) - go to the declaration of TIME_FORMAT_PREF for further details. + return getIntegerPreference(context, TIME_FORMAT_PREF, -1) + } + + @JvmStatic + fun setTimeFormatPref(context: Context, value: Int) { setIntegerPreference(context, TIME_FORMAT_PREF, value) } } } From 7812667e691346065b73e6683e49d00cacfb209a Mon Sep 17 00:00:00 2001 From: alansley Date: Fri, 30 Aug 2024 06:25:36 +1000 Subject: [PATCH 2/5] Merge branch 'strings-squashed' into SES360-time-date-formats --- .../conversation/disappearingmessages/DisappearingMessages.kt | 1 - app/src/main/res/xml/preferences_privacy.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt index e086c95924..08a2c5195b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt @@ -19,7 +19,6 @@ import org.session.libsession.utilities.getExpirationTypeDisplayValue import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.showSessionDialog import org.thoughtcrime.securesms.ui.getSubbedCharSequence -import org.thoughtcrime.securesms.ui.getSubbedString import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds diff --git a/app/src/main/res/xml/preferences_privacy.xml b/app/src/main/res/xml/preferences_privacy.xml index b4082bd125..516a10b1b6 100644 --- a/app/src/main/res/xml/preferences_privacy.xml +++ b/app/src/main/res/xml/preferences_privacy.xml @@ -39,7 +39,7 @@ android:key="pref_typing_indicators" android:title="@string/typingIndicators" android:summary="@string/typingIndicatorsDescription" /> - + From 31b7ee3ae06c32af3b9591174492c18a40392533 Mon Sep 17 00:00:00 2001 From: alansley Date: Fri, 30 Aug 2024 06:42:51 +1000 Subject: [PATCH 3/5] WIP --- .../thoughtcrime/securesms/util/DateUtils.kt | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt index 2d200784f9..5e8d484eaa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt @@ -46,9 +46,12 @@ object DateUtils : android.text.format.DateUtils() { // We set them as invalid on startup (range is 0..8 and 0..2 respectively) so we only have to // retrieve the preference once rather than every time we wish to format a date or time. // See: TextSecurePreferences.DATE_FORMAT_PREF and TextSecurePreferences for further details. + private var userPreferredTimeFormat: Int = -1 private var userPreferredDateFormat: Int = -1 - private var userPreferredTimeFormat: Int = 2//-1 + // String for the actual date format pattern that `userPreferredDataFormat` equates to - we'll + // start it off as a sane default. + private var userPreferredDateFormatPattern = "dd/MM/YYYY" private fun isWithin(millis: Long, span: Long, unit: TimeUnit): Boolean { return System.currentTimeMillis() - millis <= unit.toMillis(span) @@ -141,8 +144,7 @@ object DateUtils : android.text.format.DateUtils() { getFormattedDateTime(timestamp, "MMM d " + getHourFormat(c), locale) } else { // NOTE: The `userPreferredDateFormat` is ONLY ever used on dates which exceed one year! - // See the Figma linked in SES-360 for details. - + // See the Figma linked in ticket SES-360 for details. Log.w("ACL", "More than 1 year") // If the date is more than a year ago then we get "19 July 2023, 16:19" type format @@ -155,7 +157,7 @@ object DateUtils : android.text.format.DateUtils() { // If no saved value was written we'll write 0 for "Follow system setting" - this will only run on first install if (userPreferredDateFormat == -1) { userPreferredDateFormat = 0 - //TextSecurePreferences.setDateFormatPref(c, userPreferredDateFormat) ACL PUT THIS BACK!!!!!!!!!!!!!!!!!!!!! + TextSecurePreferences.setDateFormatPref(c, userPreferredDateFormat) } // If the preferred date format is "Follow system setting" then we need to find out what the system setting is! @@ -164,19 +166,28 @@ object DateUtils : android.text.format.DateUtils() { // Check if the DateFormat instance is a SimpleDateFormat if (dateFormat is SimpleDateFormat) { + val dateFormatPattern = dateFormat.toLocalizedPattern() Log.w("ACL", "Date pattern: " + dateFormat.toPattern()) - when (dateFormat) { - "M/d/yy" -> FFS + when (dateFormatPattern) { + "M/d/yy" -> { userPreferredDateFormat = 1; userPreferredDateFormatPattern = dateFormatPattern } + "d/M/yy" -> { userPreferredDateFormat = 2; userPreferredDateFormatPattern = dateFormatPattern } + "dd/MM/yyyy" -> { userPreferredDateFormat = 3; userPreferredDateFormatPattern = dateFormatPattern } + "dd.MM.yyyy" -> { userPreferredDateFormat = 4; userPreferredDateFormatPattern = dateFormatPattern } + "dd-MM-yyyy" -> { userPreferredDateFormat = 5; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy/M/d" -> { userPreferredDateFormat = 6; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy.M.d" -> { userPreferredDateFormat = 7; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy-M-d" -> { userPreferredDateFormat = 8; userPreferredDateFormatPattern = dateFormatPattern } + else -> { + userPreferredDateFormat = 3; userPreferredDateFormatPattern = "dd/MM/yyyy" // Sane fallback + } } - - } else { // If the dateFormat isn't a SimpleDateFormat from which we can extract a pattern then the best - // we can do is pick a sensible default like DD/MM/YYYY - which equates to option 3 out of our + // we can do is pick a sensible default like dd/MM/YYYY - which equates to option 3 out of our // available options (see TextSecurePreferences.DATE_FORMAT_PREF for further details). userPreferredDateFormat = 3 - // IMPORTANT: We don't WRITE this to the pref - we just use it while the app is running! + // IMPORTANT: We don't WRITE this to the pref so that "Follow system setting" remains - we just use it while the app is running! } // Set the time format we'll use to either 24 or 12 hours. From 4094b84f7db62357c290d68107e68273e7b9ddd4 Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Fri, 30 Aug 2024 09:09:31 +1000 Subject: [PATCH 4/5] Further WIP --- .../thoughtcrime/securesms/util/DateUtils.kt | 135 ++++++++++++------ 1 file changed, 93 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt index 5e8d484eaa..6c4fa5b527 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt @@ -46,11 +46,14 @@ object DateUtils : android.text.format.DateUtils() { // We set them as invalid on startup (range is 0..8 and 0..2 respectively) so we only have to // retrieve the preference once rather than every time we wish to format a date or time. // See: TextSecurePreferences.DATE_FORMAT_PREF and TextSecurePreferences for further details. + // Note: For testing you can just set these values to something which isn't -1 and it will + // bypass the retrieve-from-pref operation and use the associated format. private var userPreferredTimeFormat: Int = -1 - private var userPreferredDateFormat: Int = -1 + private var userPreferredDateFormat: Int = 7 // String for the actual date format pattern that `userPreferredDataFormat` equates to - we'll - // start it off as a sane default. + // start it off as a sane default, and update it to either follow the system or a specific + // format as the user desires. private var userPreferredDateFormatPattern = "dd/MM/YYYY" private fun isWithin(millis: Long, span: Long, unit: TimeUnit): Boolean { @@ -92,9 +95,12 @@ object DateUtils : android.text.format.DateUtils() { } // THIS IS THE METHOD THAT ACTUALLY GETS USED TO GET THE DATE TIME - fun getFormattedDateTime(time: Long, template: String, locale: Locale): String { + fun getFormattedDateTime(timestamp: Long, template: String, locale: Locale): String { + + Log.w("ACL", "Getting formatted datetime - template is: " + template) val localizedPattern = getLocalizedPattern(template, locale) - return SimpleDateFormat(localizedPattern, locale).format(Date(time)) + Log.w("ACL", "Which turns into localizedPattern: " + localizedPattern) + return SimpleDateFormat(template, locale).format(Date(timestamp)) } // Method to get the user's preferred time format, whether that's 12-hour or 24-hour @@ -126,8 +132,53 @@ object DateUtils : android.text.format.DateUtils() { return if (userPreferredTimeFormat == 1) "hh:mm a" else "HH:mm" } + // Method to take the SimpleDateFormat.getPattern() string and set the user's preferred date format appropriately + private fun updateDateFormatSettingsFromPattern(dateFormatPattern: String) { + when (dateFormatPattern) { + "M/d/yy" -> { userPreferredDateFormat = 1; userPreferredDateFormatPattern = dateFormatPattern } + "d/M/yy" -> { userPreferredDateFormat = 2; userPreferredDateFormatPattern = dateFormatPattern } + "dd/MM/yyyy" -> { userPreferredDateFormat = 3; userPreferredDateFormatPattern = dateFormatPattern } + "dd.MM.yyyy" -> { userPreferredDateFormat = 4; userPreferredDateFormatPattern = dateFormatPattern } + "dd-MM-yyyy" -> { userPreferredDateFormat = 5; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy/M/d" -> { userPreferredDateFormat = 6; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy.M.d" -> { userPreferredDateFormat = 7; userPreferredDateFormatPattern = dateFormatPattern } + "yyyy-M-d" -> { userPreferredDateFormat = 8; userPreferredDateFormatPattern = dateFormatPattern } + else -> { + // Sane fallback for unrecognised date format patten + userPreferredDateFormat = 3; userPreferredDateFormatPattern = "dd/MM/yyyy" + } + } + } + + // Method to take an int from the user's dateFormatPref and update our date format pattern accordingly + private fun updateDateFormatSettingsFromInt(dateFormatPrefInt: Int) { + var mutableDateFormatPrefInt = dateFormatPrefInt + // There's probably a more elegant way to do this - but we can't use `.also { }` because + // the else block + when (mutableDateFormatPrefInt) { + 1 -> { userPreferredDateFormatPattern = "M/d/yy" } + 2 -> { userPreferredDateFormatPattern = "d/M/yy" } + 3 -> { userPreferredDateFormatPattern = "dd/MM/yyyy" } + 4 -> { userPreferredDateFormatPattern = "dd.MM.yyyy" } + 5 -> { userPreferredDateFormatPattern = "dd-MM-yyyy" } + 6 -> { userPreferredDateFormatPattern = "yyyy/M/d" } + 7 -> { userPreferredDateFormatPattern = "yyyy.M.d" } + 8 -> { userPreferredDateFormatPattern = "yyyy-M-d" } + else -> { + // Sane fallback for unrecognised date format pattern ("dd/MM/yyyy") + Log.w("DateUtils", "Bad dateFormatPrefInt - falling back to dd/MM/yyyy") + mutableDateFormatPrefInt = 3 // Because we 'also' update our setting from this! + userPreferredDateFormatPattern = "dd/MM/yyyy" + } + }.also { + // Typically we pass in `userPreferredDataFormat` TO this method - but because we perform + // sanitisation in the case of a bad value we'll also write a cleaned version back to the var. + userPreferredDateFormat = mutableDateFormatPrefInt + } + } + fun getDisplayFormattedTimeSpanString(c: Context, locale: Locale, timestamp: Long): String { - // Note: Date-formats are in TR-35 format. + // Note: Date patterns are in TR-35 format. // See: https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns val t = if (isToday(timestamp)) { Log.w("ACL", "Within today") @@ -149,55 +200,55 @@ object DateUtils : android.text.format.DateUtils() { Log.w("ACL", "More than 1 year") // If the date is more than a year ago then we get "19 July 2023, 16:19" type format - // If this is the first run.. + // If the app has just started.. if (userPreferredDateFormat == -1) { // ..update our preferred date format (will return -1 if no saved pref). userPreferredDateFormat = TextSecurePreferences.getDateFormatPref(c) - // If no saved value was written we'll write 0 for "Follow system setting" - this will only run on first install + // If we don't have a saved date format pref we'll write 0 for "Follow system setting". + // Note: This will only execute on first install & run where the pref doesn't exist. if (userPreferredDateFormat == -1) { userPreferredDateFormat = 0 TextSecurePreferences.setDateFormatPref(c, userPreferredDateFormat) } + } + + // --- At this point we will always have _some_ preferred date format --- + + // If the preferred date format is "Follow system setting" then we need to find out what the system setting is! + if (userPreferredDateFormat == 0) { + val dateFormat = DateFormat.getDateFormat(c) - // If the preferred date format is "Follow system setting" then we need to find out what the system setting is! - if (userPreferredDateFormat == 0) { - val dateFormat = DateFormat.getDateFormat(c) - - // Check if the DateFormat instance is a SimpleDateFormat - if (dateFormat is SimpleDateFormat) { - val dateFormatPattern = dateFormat.toLocalizedPattern() - Log.w("ACL", "Date pattern: " + dateFormat.toPattern()) - - when (dateFormatPattern) { - "M/d/yy" -> { userPreferredDateFormat = 1; userPreferredDateFormatPattern = dateFormatPattern } - "d/M/yy" -> { userPreferredDateFormat = 2; userPreferredDateFormatPattern = dateFormatPattern } - "dd/MM/yyyy" -> { userPreferredDateFormat = 3; userPreferredDateFormatPattern = dateFormatPattern } - "dd.MM.yyyy" -> { userPreferredDateFormat = 4; userPreferredDateFormatPattern = dateFormatPattern } - "dd-MM-yyyy" -> { userPreferredDateFormat = 5; userPreferredDateFormatPattern = dateFormatPattern } - "yyyy/M/d" -> { userPreferredDateFormat = 6; userPreferredDateFormatPattern = dateFormatPattern } - "yyyy.M.d" -> { userPreferredDateFormat = 7; userPreferredDateFormatPattern = dateFormatPattern } - "yyyy-M-d" -> { userPreferredDateFormat = 8; userPreferredDateFormatPattern = dateFormatPattern } - else -> { - userPreferredDateFormat = 3; userPreferredDateFormatPattern = "dd/MM/yyyy" // Sane fallback - } - } - } else { - // If the dateFormat isn't a SimpleDateFormat from which we can extract a pattern then the best - // we can do is pick a sensible default like dd/MM/YYYY - which equates to option 3 out of our - // available options (see TextSecurePreferences.DATE_FORMAT_PREF for further details). - userPreferredDateFormat = 3 - // IMPORTANT: We don't WRITE this to the pref so that "Follow system setting" remains - we just use it while the app is running! - } - - // Set the time format we'll use to either 24 or 12 hours. - // IMPORTANT: We don't WRITE this to the pref - we just use it while the app is running! - // Note: See TextSecurePreferences.TIME_FORMAT_PREF for further details of available formats. - //userPreferredTimeFormat = if (is24HourFormat) 2 else 1 + // Check if the DateFormat instance is a SimpleDateFormat + if (dateFormat is SimpleDateFormat) { + val dateFormatPattern = dateFormat.toLocalizedPattern() + Log.w("ACL", "Date pattern: " + dateFormat.toPattern()) + + // System setting has a date format pattern? Cool - let's use it, whatever it might be + userPreferredDateFormatPattern = dateFormatPattern + + // Update our userPreferredDateFormat & pattern from the system setting + //updateDateFormatSettingsFromPattern(dateFormatPattern) + } else { + // If the dateFormat ISN'T a SimpleDateFormat from which we can extract a pattern then the best + // we can do is pick a sensible default like dd/MM/YYYY - which equates to option 3 out of our + // available options (see TextSecurePreferences.DATE_FORMAT_PREF for further details). + userPreferredDateFormat = 3 + userPreferredDateFormatPattern = "dd/MM/yyyy" } + + // IMPORTANT: We neverdon't WRITE this to the pref so that "Follow system setting" remains + // - we just use it while the app is running! + + } else { + // If the user has asked for a specific date format that isn't "Follow system setting" + // then update our date formatting settings from that preference. + updateDateFormatSettingsFromInt(userPreferredDateFormat) } - getFormattedDateTime(timestamp, "MMM d " + getHourFormat(c) + ", yyyy", locale) + //userPreferredDateFormatPattern + getFormattedDateTime(timestamp, userPreferredDateFormatPattern, locale) + //getFormattedDateTime(timestamp, "MMM d " + getHourFormat(c) + ", yyyy", locale) } Log.w("ACL", "t is: $t") From a654fd6c38862deac31431a4098676e8df192128 Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Fri, 30 Aug 2024 10:40:29 +1000 Subject: [PATCH 5/5] WIP --- .../org/thoughtcrime/securesms/util/DateUtils.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt index 6c4fa5b527..b8dd93b84b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt @@ -176,6 +176,9 @@ object DateUtils : android.text.format.DateUtils() { userPreferredDateFormat = mutableDateFormatPrefInt } } + + private fun isWithinOneWeek(timestamp: Long) = System.currentTimeMillis() - timestamp <= TimeUnit.DAYS.toMillis(7) + private fun isWithinOneYear(timestamp: Long) = System.currentTimeMillis() - timestamp <= TimeUnit.DAYS.toMillis(365) fun getDisplayFormattedTimeSpanString(c: Context, locale: Locale, timestamp: Long): String { // Note: Date patterns are in TR-35 format. @@ -184,11 +187,11 @@ object DateUtils : android.text.format.DateUtils() { Log.w("ACL", "Within today") // If it's within the last 24 hours we just give the time in 24-hour format, such as "13:27" for 1:27pm getFormattedDateTime(timestamp, getHourFormat(c), locale) - } else if (isWithin(timestamp, 6, TimeUnit.DAYS)) { + } else if (isWithinOneWeek(timestamp)) { Log.w("ACL", "Within week") // If it's within the last week we give the day as 3 letters then the time in 24-hour format, such as "Fri 13:27" for Friday 1:27pm getFormattedDateTime(timestamp, "EEE " + getHourFormat(c), locale) - } else if (isWithin(timestamp, 365, TimeUnit.DAYS)) { + } else if (isWithinOneYear(timestamp)) { Log.w("ACL", "Within year") // If it's within the last year we give the month as 3 letters then the time in 24-hour format, such as "Mar 13:27" for March 1:27pm // CAREFUL: "MMM d + getHourFormat(c)" actually turns out to be "8 July, 17:14" etc. - it is DAY-NUMBER and then MONTH (which can go up to 4 chars) - and THEN the time. Wild. @@ -237,9 +240,9 @@ object DateUtils : android.text.format.DateUtils() { userPreferredDateFormatPattern = "dd/MM/yyyy" } - // IMPORTANT: We neverdon't WRITE this to the pref so that "Follow system setting" remains - // - we just use it while the app is running! - + // IMPORTANT: As we've updated the `userPreferredDataFormat` from "follow system setting" to + // "whatever that system setting is" we DO NOT write that back to the pref - we leave the + // saved value as is so that it always uses that system settings, whatever that may be. } else { // If the user has asked for a specific date format that isn't "Follow system setting" // then update our date formatting settings from that preference. @@ -278,7 +281,7 @@ object DateUtils : android.text.format.DateUtils() { } else if (isYesterday(timestamp)) { getLocalisedRelativeDayString(RelativeDay.YESTERDAY) } else { - getFormattedDateTime(timestamp, "EEE, MMM d, yyyy", locale) + getFormattedDateTime(timestamp, userPreferredDateFormatPattern, locale) } }