Skip to content

Commit 5365b07

Browse files
authored
Split dateformat into date and time and overnote and note view (#961)
1 parent e4195ff commit 5365b07

31 files changed

Lines changed: 392 additions & 174 deletions

File tree

.github/workflows/update-translation-coverage.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ name: Update Translation Coverage in README
22

33
on:
44
push:
5+
branches:
6+
- main
57
paths:
68
- app/src/main/res/values*/strings.xml
79
workflow_dispatch:

TRANSLATIONS.md

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,34 @@ See [Android Translations Converter](https://github.com/Crustack/android-transla
1919
<!-- translations:start -->
2020
| Language | Coverage |
2121
|----------|----------|
22-
| 🇺🇸 English | 100% (347/347) |
23-
| 🇪🇸 Catalan | 18% (65/347) |
24-
| 🇨🇿 Czech | 96% (336/347) |
25-
| 🇩🇰 Danish | 19% (69/347) |
26-
| 🇩🇪 German | 96% (336/347) |
27-
| 🇬🇷 Greek | 20% (72/347) |
28-
| 🇪🇸 Spanish | 90% (315/347) |
29-
| 🇫🇷 French | 94% (328/347) |
30-
| 🇭🇺 Hungarian | 18% (65/347) |
31-
| 🇮🇩 Indonesian | 21% (75/347) |
32-
| 🇮🇹 Italian | 84% (292/347) |
33-
| 🇯🇵 Japanese | 21% (73/347) |
34-
| 🇲🇲 Burmese | 26% (91/347) |
35-
| 🇳🇴 Norwegian Bokmål | 30% (107/347) |
36-
| 🇳🇱 Dutch | 61% (213/347) |
37-
| 🇳🇴 Norwegian Nynorsk | 30% (107/347) |
38-
| 🇵🇱 Polish | 86% (301/347) |
39-
| 🇧🇷 Portuguese (Brazil) | 90% (313/347) |
40-
| 🇵🇹 Portuguese (Portugal) | 20% (71/347) |
41-
| 🇷🇴 Romanian | 87% (302/347) |
42-
| 🇷🇺 Russian | 88% (306/347) |
43-
| 🇸🇰 Slovak | 18% (65/347) |
44-
| 🇸🇮 Slovenian | 31% (110/347) |
45-
| 🇸🇪 Swedish | 18% (63/347) |
46-
| 🇵🇭 Tagalog | 18% (65/347) |
47-
| 🇹🇷 Turkish | 21% (73/347) |
48-
| 🇺🇦 Ukrainian | 95% (332/347) |
49-
| 🇻🇳 Vietnamese | 31% (108/347) |
50-
| 🇨🇳 Chinese (Simplified) | 98% (341/347) |
51-
| 🇹🇼 Chinese (Traditional) | 85% (295/347) |
22+
| 🇺🇸 English | 100% (353/353) |
23+
| 🇪🇸 Catalan | 18% (65/353) |
24+
| 🇨🇿 Czech | 94% (335/353) |
25+
| 🇩🇰 Danish | 19% (69/353) |
26+
| 🇩🇪 German | 94% (335/353) |
27+
| 🇬🇷 Greek | 20% (72/353) |
28+
| 🇪🇸 Spanish | 88% (314/353) |
29+
| 🇫🇷 French | 92% (327/353) |
30+
| 🇭🇺 Hungarian | 18% (65/353) |
31+
| 🇮🇩 Indonesian | 21% (75/353) |
32+
| 🇮🇹 Italian | 82% (291/353) |
33+
| 🇯🇵 Japanese | 20% (73/353) |
34+
| 🇲🇲 Burmese | 25% (91/353) |
35+
| 🇳🇴 Norwegian Bokmål | 30% (107/353) |
36+
| 🇳🇱 Dutch | 60% (213/353) |
37+
| 🇳🇴 Norwegian Nynorsk | 30% (107/353) |
38+
| 🇵🇱 Polish | 84% (300/353) |
39+
| 🇧🇷 Portuguese (Brazil) | 88% (312/353) |
40+
| 🇵🇹 Portuguese (Portugal) | 20% (71/353) |
41+
| 🇷🇴 Romanian | 85% (301/353) |
42+
| 🇷🇺 Russian | 86% (305/353) |
43+
| 🇸🇰 Slovak | 18% (65/353) |
44+
| 🇸🇮 Slovenian | 31% (110/353) |
45+
| 🇸🇪 Swedish | 17% (63/353) |
46+
| 🇵🇭 Tagalog | 18% (65/353) |
47+
| 🇹🇷 Turkish | 20% (73/353) |
48+
| 🇺🇦 Ukrainian | 93% (331/353) |
49+
| 🇻🇳 Vietnamese | 30% (108/353) |
50+
| 🇨🇳 Chinese (Simplified) | 96% (340/353) |
51+
| 🇹🇼 Chinese (Traditional) | 83% (294/353) |
5252
<!-- translations:end -->

app/src/main/java/com/philkes/notallyx/presentation/UiExtensions.kt

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,16 @@ import com.philkes.notallyx.presentation.view.note.listitem.ListManager
110110
import com.philkes.notallyx.presentation.view.note.listitem.adapter.ListItemVH
111111
import com.philkes.notallyx.presentation.viewmodel.BaseNoteModel
112112
import com.philkes.notallyx.presentation.viewmodel.preference.DateFormat
113+
import com.philkes.notallyx.presentation.viewmodel.preference.TimeFormat
113114
import com.philkes.notallyx.presentation.viewmodel.preference.displayBodySize
114115
import com.philkes.notallyx.utils.changehistory.ChangeHistory
115116
import com.philkes.notallyx.utils.changehistory.EditTextState
116117
import com.philkes.notallyx.utils.changehistory.EditTextWithHistoryChange
117118
import com.philkes.notallyx.utils.getUrl
118-
import java.text.SimpleDateFormat
119119
import java.util.Date
120-
import java.util.Locale
121120
import me.zhanghai.android.fastscroll.FastScrollNestedScrollView
122121
import me.zhanghai.android.fastscroll.FastScrollerBuilder
123122
import me.zhanghai.android.fastscroll.PopupStyles
124-
import org.ocpsoft.prettytime.PrettyTime
125123

126124
/**
127125
* For some reason, this method crashes sometimes with an IndexOutOfBoundsException that I've not
@@ -290,12 +288,14 @@ fun ViewGroup.addIconButton(
290288
fun TextView.displayFormattedTimestamp(
291289
timestamp: Long?,
292290
dateFormat: DateFormat,
291+
timeFormat: TimeFormat,
293292
prefixResId: Int? = null,
294293
) {
295-
if (dateFormat != DateFormat.NONE && timestamp != null) {
294+
if ((dateFormat != DateFormat.NONE || timeFormat != TimeFormat.NONE) && timestamp != null) {
296295
visibility = View.VISIBLE
297296
text =
298-
"${prefixResId?.let { getString(it) } ?: ""} ${formatTimestamp(timestamp, dateFormat)}"
297+
"${prefixResId?.let { getString(it) } ?: ""} ${Date(timestamp).format(dateFormat, timeFormat)}"
298+
.trim()
299299
} else visibility = View.GONE
300300
}
301301

@@ -456,6 +456,17 @@ fun <T, C> NotNullLiveData<T>.merge(liveData: NotNullLiveData<C>): MediatorLiveD
456456
}
457457
}
458458

459+
fun <T, C, B> NotNullLiveData<T>.merge(
460+
liveData: NotNullLiveData<C>,
461+
liveData2: NotNullLiveData<B>,
462+
): MediatorLiveData<Triple<T, C, B>> {
463+
return MediatorLiveData<Triple<T, C, B>>().apply {
464+
addSource(this@merge) { value1 -> value = Triple(value1, liveData.value, liveData2.value) }
465+
addSource(liveData) { value2 -> value = Triple(this@merge.value, value2, liveData2.value) }
466+
addSource(liveData2) { value3 -> value = Triple(this@merge.value, liveData.value, value3) }
467+
}
468+
}
469+
459470
fun <T, C> NotNullLiveData<T>.merge(liveData: LiveData<C>): MediatorLiveData<Pair<T, C?>> {
460471
return MediatorLiveData<Pair<T, C?>>().apply {
461472
addSource(this@merge) { value1 -> value = Pair(value1, liveData.value) }
@@ -612,29 +623,28 @@ fun Context.displayEditLabelDialog(
612623
}
613624
}
614625

615-
private fun formatTimestamp(timestamp: Long, dateFormat: DateFormat): String {
616-
return Date(timestamp).format(dateFormat)
617-
}
626+
fun Date.format(
627+
dateFormat: DateFormat = DateFormat.DD_MM_YY_GER,
628+
timeFormat: TimeFormat = TimeFormat.TWENTY_FOUR_H,
629+
ensureFullFormat: Boolean = false,
630+
): String {
631+
val (effectiveDateFormat, effectiveTimeFormat) =
632+
if (ensureFullFormat && dateFormat != DateFormat.RELATIVE) {
633+
Pair(
634+
dateFormat.takeIf { it != DateFormat.NONE } ?: DateFormat.DD_MM_YY_GER,
635+
timeFormat.takeIf { it != TimeFormat.NONE } ?: TimeFormat.TWENTY_FOUR_H,
636+
)
637+
} else Pair(dateFormat, timeFormat)
638+
if (effectiveDateFormat == DateFormat.NONE && effectiveTimeFormat == TimeFormat.NONE) {
639+
return ""
640+
}
641+
val datePart = effectiveDateFormat.format(this)
642+
val timePart = effectiveTimeFormat.format(this)
618643

619-
private val ISO_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US)
620-
621-
fun Date.format(dateFormat: DateFormat = DateFormat.TIMESTAMP_SHORT): String {
622-
return when (dateFormat) {
623-
DateFormat.NONE -> ""
624-
DateFormat.RELATIVE -> PrettyTime().format(this)
625-
DateFormat.ABSOLUTE ->
626-
java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL).format(this)
627-
DateFormat.ABSOLUTE_SHORT ->
628-
java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT).format(this)
629-
DateFormat.SHORT_ISO -> {
630-
ISO_DATE_FORMAT.format(this)
631-
}
632-
DateFormat.TIMESTAMP_SHORT ->
633-
java.text.DateFormat.getDateTimeInstance(
634-
java.text.DateFormat.SHORT,
635-
java.text.DateFormat.SHORT,
636-
)
637-
.format(this)
644+
return if (datePart.isNotEmpty() && timePart.isNotEmpty()) {
645+
"$datePart $timePart"
646+
} else {
647+
datePart + timePart
638648
}
639649
}
640650

@@ -1142,7 +1152,12 @@ fun Context.createTextView(textResId: Int, padding: Int = 16.dp): TextView {
11421152
}
11431153
}
11441154

1145-
fun Chip.setupReminderChip(baseNote: BaseNote, textSize: Float? = null) {
1155+
fun Chip.setupReminderChip(
1156+
baseNote: BaseNote,
1157+
dateFormat: DateFormat,
1158+
timeFormat: TimeFormat,
1159+
textSize: Float? = null,
1160+
) {
11461161
val now = Date(System.currentTimeMillis())
11471162
val mostRecentNotificationDate =
11481163
baseNote.reminders.findNextNotificationDate()
@@ -1153,7 +1168,7 @@ fun Chip.setupReminderChip(baseNote: BaseNote, textSize: Float? = null) {
11531168
}
11541169
this.apply {
11551170
visibility = VISIBLE
1156-
text = mostRecentNotificationDate.format()
1171+
text = mostRecentNotificationDate.format(dateFormat, timeFormat, ensureFullFormat = true)
11571172
textSize?.let {
11581173
setTextSizeSp(it)
11591174
chipIconSize =

app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/NotallyFragment.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ abstract class NotallyFragment : Fragment(), ItemListener {
262262
with(model.preferences) {
263263
BaseNoteAdapter(
264264
model.actionMode.selectedIds,
265-
dateFormat.value,
265+
dateFormatOverview.value,
266+
timeFormatOverview.value,
266267
notesAdapterSortCallback(),
267268
BaseNoteVHPreferences(
268269
textSizeOverview.value,

app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/PreferenceBindingExtensions.kt

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.google.android.material.slider.Slider
1515
import com.google.android.material.textfield.TextInputLayout.END_ICON_PASSWORD_TOGGLE
1616
import com.philkes.notallyx.R
1717
import com.philkes.notallyx.databinding.ChoiceItemBinding
18+
import com.philkes.notallyx.databinding.DialogDatetimeFormatBinding
1819
import com.philkes.notallyx.databinding.DialogNotesSortBinding
1920
import com.philkes.notallyx.databinding.DialogPreferenceBooleanBinding
2021
import com.philkes.notallyx.databinding.DialogPreferenceEnumWithToggleBinding
@@ -47,6 +48,7 @@ import com.philkes.notallyx.presentation.viewmodel.preference.SortDirection
4748
import com.philkes.notallyx.presentation.viewmodel.preference.StringPreference
4849
import com.philkes.notallyx.presentation.viewmodel.preference.TextProvider
4950
import com.philkes.notallyx.presentation.viewmodel.preference.Theme
51+
import com.philkes.notallyx.presentation.viewmodel.preference.TimeFormat
5052
import com.philkes.notallyx.utils.canAuthenticateWithBiometrics
5153
import com.philkes.notallyx.utils.toReadablePath
5254

@@ -191,55 +193,6 @@ fun PreferenceBinding.setup(
191193
}
192194
}
193195

194-
fun PreferenceBinding.setup(
195-
dateFormatPreference: EnumPreference<DateFormat>,
196-
dateFormatValue: DateFormat,
197-
applyToNoteViewValue: Boolean,
198-
context: Context,
199-
layoutInflater: LayoutInflater,
200-
onSave: (dateFormat: DateFormat, applyToEditMode: Boolean) -> Unit,
201-
) {
202-
Title.setText(dateFormatPreference.titleResId!!)
203-
204-
Value.text = dateFormatValue.getText(context)
205-
206-
root.setOnClickListener {
207-
val layout = DialogPreferenceEnumWithToggleBinding.inflate(layoutInflater, null, false)
208-
layout.EnumHint.apply {
209-
setText(R.string.date_format_hint)
210-
isVisible = true
211-
}
212-
DateFormat.entries.forEachIndexed { idx, dateFormat ->
213-
ChoiceItemBinding.inflate(layoutInflater).root.apply {
214-
id = idx
215-
text = dateFormat.getText(context)
216-
tag = dateFormat
217-
layout.EnumRadioGroup.addView(this)
218-
if (dateFormat == dateFormatValue) {
219-
layout.EnumRadioGroup.check(this.id)
220-
}
221-
}
222-
}
223-
224-
layout.Toggle.apply {
225-
setText(R.string.date_format_apply_in_note_view)
226-
isChecked = applyToNoteViewValue
227-
}
228-
229-
MaterialAlertDialogBuilder(context)
230-
.setTitle(dateFormatPreference.titleResId)
231-
.setView(layout.root)
232-
.setPositiveButton(R.string.save) { dialog, _ ->
233-
dialog.cancel()
234-
val dateFormat = layout.EnumRadioGroup.checkedTag() as DateFormat
235-
val applyToNoteView = layout.Toggle.isChecked
236-
onSave(dateFormat, applyToNoteView)
237-
}
238-
.setCancelButton()
239-
.show()
240-
}
241-
}
242-
243196
fun PreferenceBinding.setup(
244197
themePreference: EnumPreference<Theme>,
245198
themeValue: Theme,
@@ -634,3 +587,67 @@ fun PreferenceBinding.setupStartView(
634587
.showAndFocus(allowFullSize = true)
635588
}
636589
}
590+
591+
fun PreferenceBinding.setupDateTimeFormat(
592+
titleResId: Int,
593+
datePreference: EnumPreference<DateFormat>,
594+
timePreference: EnumPreference<TimeFormat>,
595+
context: Context,
596+
layoutInflater: LayoutInflater,
597+
onSave: (dateFormat: DateFormat, timeFormat: TimeFormat) -> Unit,
598+
) {
599+
Title.setText(titleResId)
600+
val updateValueText = {
601+
val dateText =
602+
if (datePreference.value == DateFormat.NONE) ""
603+
else datePreference.value.getText(context)
604+
val timeText =
605+
if (timePreference.value == TimeFormat.NONE) ""
606+
else timePreference.value.getText(context)
607+
Value.text =
608+
when {
609+
datePreference.value == DateFormat.NONE &&
610+
timePreference.value == TimeFormat.NONE ->
611+
datePreference.value.getText(context) // Shows "None"
612+
datePreference.value == DateFormat.NONE -> timeText
613+
timePreference.value == TimeFormat.NONE -> dateText
614+
else -> "$dateText $timeText"
615+
}
616+
}
617+
updateValueText()
618+
619+
root.setOnClickListener {
620+
val layout = DialogDatetimeFormatBinding.inflate(layoutInflater, null, false)
621+
var selectedDate = datePreference.value
622+
var selectedTime = timePreference.value
623+
624+
val dateEntries = DateFormat.entries.map { it.getText(context) }.toTypedArray()
625+
layout.DateSelectionBox.apply {
626+
setSimpleItems(dateEntries)
627+
select(selectedDate.getText(context))
628+
setOnItemClickListener { _, _, position, _ ->
629+
selectedDate = DateFormat.entries[position]
630+
}
631+
}
632+
633+
val timeEntries = TimeFormat.entries.map { it.getText(context) }.toTypedArray()
634+
layout.TimeSelectionBox.apply {
635+
setSimpleItems(timeEntries)
636+
select(selectedTime.getText(context))
637+
setOnItemClickListener { _, _, position, _ ->
638+
selectedTime = TimeFormat.entries[position]
639+
}
640+
}
641+
642+
MaterialAlertDialogBuilder(context)
643+
.setTitle(titleResId)
644+
.setView(layout.root)
645+
.setPositiveButton(R.string.save) { dialog, _ ->
646+
dialog.cancel()
647+
onSave(selectedDate, selectedTime)
648+
updateValueText()
649+
}
650+
.setCancelButton()
651+
.showAndFocus(allowFullSize = true)
652+
}
653+
}

0 commit comments

Comments
 (0)