diff --git a/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt b/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt index c8e384fb4b57..9a1888598974 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt @@ -15,8 +15,8 @@ import androidx.test.platform.app.InstrumentationRegistry import com.nextcloud.client.database.entity.UploadEntity import com.nextcloud.client.database.entity.toOCUpload import com.nextcloud.client.database.entity.toUploadEntity +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R -import com.owncloud.android.utils.DisplayUtils import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull @@ -188,7 +188,7 @@ class UploadDateTests { minResolution: Long = DateUtils.MINUTE_IN_MILLIS, showFuture: Boolean = false ) { - val result = DisplayUtils.getRelativeDateTimeString( + val result = DisplayTextFormatter.formatRelativeDateTime( context, time, minResolution, diff --git a/app/src/main/java/com/nextcloud/client/player/ui/audio/AudioFileFragment.kt b/app/src/main/java/com/nextcloud/client/player/ui/audio/AudioFileFragment.kt index 65c49a651623..96b0368b1d5e 100644 --- a/app/src/main/java/com/nextcloud/client/player/ui/audio/AudioFileFragment.kt +++ b/app/src/main/java/com/nextcloud/client/player/ui/audio/AudioFileFragment.kt @@ -21,9 +21,9 @@ import com.nextcloud.client.player.model.state.PlaybackState import com.nextcloud.client.player.util.PlayerUtil.getPlaybackFile import com.nextcloud.client.player.util.PlayerUtil.putPlaybackFile import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.databinding.PlayerAudioFileFragmentBinding -import com.owncloud.android.utils.DisplayUtils import dagger.android.support.AndroidSupportInjection import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -138,7 +138,7 @@ open class AudioFileFragment : ).joinToString(DETAILS_SEPARATOR) private fun getLastModifiedText(lastModified: Long): String { - val relativeTimestamp = DisplayUtils.getRelativeTimestamp(context, lastModified) + val relativeTimestamp = DisplayTextFormatter.formatRelativeTimestamp(requireContext(), lastModified) return getString(R.string.player_last_modified, relativeTimestamp) } } diff --git a/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt index 3ac1e4a8a25f..f3b8c260e83e 100644 --- a/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/SetStatusMessageBottomSheet.kt @@ -29,6 +29,7 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.di.Injectable import com.nextcloud.utils.SnackbarUtil +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.databinding.SetStatusMessageBottomSheetBinding import com.owncloud.android.datamodel.ArbitraryDataProvider @@ -38,7 +39,6 @@ import com.owncloud.android.lib.resources.users.Status import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.adapter.PredefinedStatusClickListener import com.owncloud.android.ui.adapter.PredefinedStatusListAdapter -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils import com.vanniktech.emoji.EmojiManager import com.vanniktech.emoji.EmojiPopup @@ -180,7 +180,7 @@ class SetStatusMessageBottomSheet(val user: User, val currentStatus: Status?) : binding.remainingClearTime.apply { binding.clearStatusMessageTextView.text = getString(R.string.clear) visibility = View.VISIBLE - text = DisplayUtils.getRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true) + text = DisplayTextFormatter.formatRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true) .toString() .replaceFirstChar { it.lowercase(Locale.getDefault()) } setOnClickListener { diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 237f72abb8ba..2e740cdc7985 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -38,6 +38,7 @@ import com.nextcloud.utils.SnackbarUtil import com.nextcloud.utils.avatar.AvatarGenerationListener import com.nextcloud.utils.avatar.AvatarGenerator import com.nextcloud.utils.extensions.setVisibleIf +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.thumbnail.ThumbnailArguments import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding @@ -304,7 +305,8 @@ class FileActionsBottomSheet : } private fun getLockedUntilText(lockInfo: FileActionsViewModel.LockInfo): CharSequence { - val relativeTimestamp = DisplayUtils.getRelativeTimestamp(context, lockInfo.lockedUntil!!, true) + val relativeTimestamp = + DisplayTextFormatter.formatRelativeTimestamp(requireContext(), lockInfo.lockedUntil!!, true) return getString(R.string.lock_expiration_info, relativeTimestamp) } diff --git a/app/src/main/java/com/nextcloud/utils/date/DateFormatPattern.kt b/app/src/main/java/com/nextcloud/utils/date/DateFormatPattern.kt index b3dd2729ae20..ff5653c4df84 100644 --- a/app/src/main/java/com/nextcloud/utils/date/DateFormatPattern.kt +++ b/app/src/main/java/com/nextcloud/utils/date/DateFormatPattern.kt @@ -26,5 +26,11 @@ enum class DateFormatPattern(val pattern: String) { /** * Aug 2026 */ - MonthWithYear("MMM yyyy") + MonthWithYear("MMM yyyy"), + + FullMonthWithYear("MMMM yyyy"), + + FullMonth("MMMM"), + + Year("yyyy") } diff --git a/app/src/main/java/com/nextcloud/utils/text/DisplayTextFormatter.kt b/app/src/main/java/com/nextcloud/utils/text/DisplayTextFormatter.kt new file mode 100644 index 000000000000..3ee11ca2baa2 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/text/DisplayTextFormatter.kt @@ -0,0 +1,86 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.text + +import android.content.Context +import android.text.format.DateUtils +import com.nextcloud.client.account.User +import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.date.DateFormatPattern +import com.owncloud.android.MainApp +import com.owncloud.android.R +import com.owncloud.android.utils.DisplayUtils +import java.text.SimpleDateFormat +import java.util.Date + +object DisplayTextFormatter { + + private const val DATE_TIME_SEPARATOR = "," + private const val TIME_SEPARATOR = ':' + private const val DATE_TIME_PARTS_SIZE = 2 + private const val ACCOUNT_HOST_SEPARATOR = '@' + + @JvmStatic + fun formatAccountName(user: User): String { + val host = user.accountName.substringAfterLast(ACCOUNT_HOST_SEPARATOR) + val displayName = user.toOwnCloudAccount().displayName + return "$displayName$ACCOUNT_HOST_SEPARATOR${DisplayUtils.convertIdn(host, false)}" + } + + @JvmStatic + @JvmOverloads + fun formatRelativeTimestamp(context: Context, timestamp: Long, showFuture: Boolean = false): CharSequence = + formatRelativeDateTime(context, timestamp, DateUtils.SECOND_IN_MILLIS, showFuture = showFuture) + + @JvmStatic + @JvmOverloads + fun formatRelativeDateTime( + context: Context, + time: Long, + minResolution: Long, + transitionResolution: Long = DateUtils.WEEK_IN_MILLIS, + flags: Int = 0, + showFuture: Boolean = false + ): CharSequence { + val elapsed = System.currentTimeMillis() - time + return when { + !showFuture && elapsed < 0 -> HumanReadableFormatter.formatDateTime(time) + + minResolution == DateUtils.MINUTE_IN_MILLIS && elapsed in 1 until DateUtils.MINUTE_IN_MILLIS -> + context.getString(R.string.file_list_seconds_ago) + + else -> DateUtils.getRelativeDateTimeString(context, time, minResolution, transitionResolution, flags) + .toString() + .withoutTimeOfDay() + } + } + + @JvmStatic + @JvmOverloads + fun formatDate(timestamp: Long, pattern: DateFormatPattern, context: Context = MainApp.getAppContext()): String { + val locale = context.resources.configuration.locales[0] + return SimpleDateFormat(pattern.pattern, locale).format(Date(timestamp)) + } + + private fun String.withoutTimeOfDay(): String { + val parts = split(DATE_TIME_SEPARATOR) + if (parts.size != DATE_TIME_PARTS_SIZE || parts.any(String::isBlank)) { + return this + } + + val (first, second) = parts + val firstHasTime = TIME_SEPARATOR in first + val secondHasTime = TIME_SEPARATOR in second + + return when { + secondHasTime && !firstHasTime -> first + firstHasTime && !secondHasTime -> second + else -> this + } + } +} diff --git a/app/src/main/java/com/owncloud/android/datamodel/GalleryItems.kt b/app/src/main/java/com/owncloud/android/datamodel/GalleryItems.kt index 44cb3175beae..7633455bc8d8 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/GalleryItems.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/GalleryItems.kt @@ -7,18 +7,13 @@ */ package com.owncloud.android.datamodel -import com.owncloud.android.utils.DisplayUtils +import com.nextcloud.utils.date.DateFormatPattern +import com.nextcloud.utils.text.DisplayTextFormatter data class GalleryItems(val date: Long, val rows: List) { override fun toString(): String { - val month = DisplayUtils.getDateByPattern( - date, - DisplayUtils.MONTH_PATTERN - ) - val year = DisplayUtils.getDateByPattern( - date, - DisplayUtils.YEAR_PATTERN - ) + val month = DisplayTextFormatter.formatDate(date, DateFormatPattern.FullMonth) + val year = DisplayTextFormatter.formatDate(date, DateFormatPattern.Year) return "$month/$year with $rows rows" } } diff --git a/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt index 1808a0541d58..de8b7a5cbd34 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt @@ -26,6 +26,7 @@ import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.common.NextcloudClient import com.nextcloud.utils.GlideHelper import com.nextcloud.utils.avatar.AvatarGenerator +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.text.RichSubjectFormatter import com.nextcloud.utils.text.RichSubjectParam import com.owncloud.android.MainApp @@ -40,7 +41,6 @@ import com.owncloud.android.lib.resources.activities.model.RichObject import com.owncloud.android.lib.resources.activities.models.PreviewObject import com.owncloud.android.ui.activities.StickyHeaderAdapter import com.owncloud.android.ui.interfaces.ActivityListInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers @@ -81,12 +81,10 @@ open class ActivityListAdapter( fun getHeaderDateString(context: Context, modificationTimestamp: Long): CharSequence = if ((System.currentTimeMillis() - modificationTimestamp) < DateUtils.WEEK_IN_MILLIS) { - DisplayUtils.getRelativeDateTimeString( + DisplayTextFormatter.formatRelativeDateTime( context, modificationTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 + DateUtils.DAY_IN_MILLIS ) } else { DateFormat.format( diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index 372a66a32c25..ee06009657f0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -23,7 +23,9 @@ import androidx.recyclerview.widget.RecyclerView import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.client.account.User +import com.nextcloud.utils.date.DateFormatPattern import com.nextcloud.utils.extensions.toGalleryItems +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.GalleryHeaderBinding @@ -36,7 +38,6 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileSortOrder import com.owncloud.android.utils.theme.ViewThemeUtils import me.zhanghai.android.fastscroll.PopupTextProvider @@ -185,10 +186,10 @@ class GalleryAdapter( } } - override fun getPopupText(p0: View, position: Int): CharSequence = DisplayUtils.getDateByPattern( + override fun getPopupText(p0: View, position: Int): CharSequence = DisplayTextFormatter.formatDate( files[getRelativePosition(position).section()].date, - context, - DisplayUtils.MONTH_YEAR_PATTERN + DateFormatPattern.FullMonthWithYear, + context ) override fun onBindHeaderViewHolder(holder: SectionedViewHolder?, section: Int, expanded: Boolean) { @@ -196,15 +197,15 @@ class GalleryAdapter( val headerViewHolder = holder as GalleryHeaderViewHolder val galleryItem = files[section] - headerViewHolder.binding.month.text = DisplayUtils.getDateByPattern( + headerViewHolder.binding.month.text = DisplayTextFormatter.formatDate( galleryItem.date, - context, - DisplayUtils.MONTH_PATTERN + DateFormatPattern.FullMonth, + context ) - headerViewHolder.binding.year.text = DisplayUtils.getDateByPattern( + headerViewHolder.binding.year.text = DisplayTextFormatter.formatDate( galleryItem.date, - context, - DisplayUtils.YEAR_PATTERN + DateFormatPattern.Year, + context ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/InternalTwoWaySyncViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/InternalTwoWaySyncViewHolder.kt index a0de99f64027..31c7c275089e 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/InternalTwoWaySyncViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/InternalTwoWaySyncViewHolder.kt @@ -11,11 +11,11 @@ import android.content.Context import android.view.View import androidx.recyclerview.widget.RecyclerView import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.databinding.InternalTwoWaySyncViewHolderBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.utils.DisplayUtils class InternalTwoWaySyncViewHolder(val binding: InternalTwoWaySyncViewHolderBinding) : RecyclerView.ViewHolder(binding.root) { @@ -41,7 +41,7 @@ class InternalTwoWaySyncViewHolder(val binding: InternalTwoWaySyncViewHolderBind if (folder.internalFolderSyncTimestamp == 0L) { syncTimestamp.text = context.getString(R.string.internal_two_way_sync_not_yet) } else { - syncTimestamp.text = DisplayUtils.getRelativeTimestamp( + syncTimestamp.text = DisplayTextFormatter.formatRelativeTimestamp( context, folder.internalFolderSyncTimestamp ) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt index 50253d15f644..1876f592693c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt @@ -30,6 +30,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.utils.avatar.AvatarGenerator import com.nextcloud.client.utils.IntentUtil import com.nextcloud.utils.extensions.setVisibleIf +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.text.RichSubjectFormatter import com.nextcloud.utils.text.RichSubjectParam import com.owncloud.android.R @@ -40,7 +41,6 @@ import com.owncloud.android.lib.resources.notifications.models.RichObject import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.fragment.notifications.NotificationsAdapterItemClick import com.owncloud.android.ui.fragment.notifications.NotificationsFragment -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("TooManyFunctions") @@ -82,7 +82,7 @@ class NotificationListAdapter( // region Bind helpers private fun bindDateTime(holder: NotificationViewHolder, notification: Notification) { - val timestamp = DisplayUtils.getRelativeTimestamp( + val timestamp = DisplayTextFormatter.formatRelativeTimestamp( fragment.requireContext(), notification.getDatetime().time ) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 4f5bc78fa046..4534efbdb3f9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -41,6 +41,7 @@ import com.nextcloud.utils.extensions.ImageViewExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; +import com.nextcloud.utils.text.DisplayTextFormatter; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.GridItemBinding; @@ -678,12 +679,12 @@ private void bindListItemViewHolder(ListItemViewHolder holder, OCFile file) { final long modificationTimestamp = file.getModificationTimestamp(); if (modificationTimestamp > 0) { - holder.getLastModification().setText(DisplayUtils.getRelativeTimestamp(activity, - modificationTimestamp)); + holder.getLastModification().setText( + DisplayTextFormatter.formatRelativeTimestamp(activity, modificationTimestamp)); holder.getLastModification().setVisibility(View.VISIBLE); } else if (file.getFirstShareTimestamp() > 0) { holder.getLastModification().setText( - DisplayUtils.getRelativeTimestamp(activity, file.getFirstShareTimestamp()) + DisplayTextFormatter.formatRelativeTimestamp(activity, file.getFirstShareTimestamp()) ); holder.getLastModification().setVisibility(View.VISIBLE); } else { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/PredefinedStatusViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/PredefinedStatusViewHolder.kt index 166673c6d6ef..bce570f8ec7a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/PredefinedStatusViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/PredefinedStatusViewHolder.kt @@ -9,10 +9,10 @@ package com.owncloud.android.ui.adapter import android.content.Context import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.databinding.PredefinedStatusBinding import com.owncloud.android.lib.resources.users.PredefinedStatus -import com.owncloud.android.utils.DisplayUtils private const val ONE_SECOND_IN_MILLIS = 1000 @@ -28,7 +28,7 @@ class PredefinedStatusViewHolder(private val binding: PredefinedStatusBinding) : } else { val clearAt = status.clearAt!! if (clearAt.type.equals("period")) { - binding.clearAt.text = DisplayUtils.getRelativeTimestamp( + binding.clearAt.text = DisplayTextFormatter.formatRelativeTimestamp( context, System.currentTimeMillis() + clearAt.time.toInt() * ONE_SECOND_IN_MILLIS, true diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ReceiveExternalFilesAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ReceiveExternalFilesAdapter.kt index e01ca8d26e25..bfce159b883f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ReceiveExternalFilesAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ReceiveExternalFilesAdapter.kt @@ -16,6 +16,7 @@ import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView import com.nextcloud.client.account.User import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.databinding.UploaderListItemLayoutBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -25,7 +26,6 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTaskObject -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils @@ -80,7 +80,8 @@ class ReceiveExternalFilesAdapter( val file = filteredFiles[position] viewHolder.binding.filename.text = file.fileName - viewHolder.binding.lastMod.text = DisplayUtils.getRelativeTimestamp(context, file.modificationTimestamp) + viewHolder.binding.lastMod.text = + DisplayTextFormatter.formatRelativeTimestamp(context, file.modificationTimestamp) if (!file.isFolder) { viewHolder.binding.fileSize.text = HumanReadableFormatter.formatBytes(file.fileLength) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java index 83e24b76791e..43bd3ed44eeb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java @@ -23,6 +23,7 @@ import com.nextcloud.utils.HumanReadableFormatter; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; +import com.nextcloud.utils.text.DisplayTextFormatter; import com.nextcloud.utils.thumbnail.VideoOverlayGenerator; import com.owncloud.android.R; import com.owncloud.android.databinding.ListFooterBinding; @@ -33,7 +34,6 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile; import com.owncloud.android.ui.interfaces.TrashbinActivityInterface; -import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -151,8 +151,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi trashbinFileViewHolder.binding.originalLocation.setText(location); // deletion time - trashbinFileViewHolder.binding.deletionTimestamp.setText(DisplayUtils.getRelativeTimestamp(context, - file.getDeletionTimestamp() * 1000)); + trashbinFileViewHolder.binding.deletionTimestamp.setText( + DisplayTextFormatter.formatRelativeTimestamp(context, file.getDeletionTimestamp() * 1000)); // checkbox if (isCheckedFile(file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/albums/AlbumsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/albums/AlbumsAdapter.kt index cef073bba01e..6298655a2910 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/albums/AlbumsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/albums/AlbumsAdapter.kt @@ -14,6 +14,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.nextcloud.utils.date.DateFormatPattern +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.thumbnail.ThumbnailArguments import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R @@ -22,7 +23,6 @@ import com.owncloud.android.databinding.AlbumsListItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.resources.albums.PhotoAlbumEntry -import com.owncloud.android.utils.DisplayUtils @Suppress("LongParameterList") class AlbumsAdapter( @@ -52,7 +52,7 @@ class AlbumsAdapter( R.plurals.album_items_text, file.nbItems, file.nbItems, - DisplayUtils.getDateByPattern(file.createdDate, DateFormatPattern.MonthWithYear.pattern) + DisplayTextFormatter.formatDate(file.createdDate, DateFormatPattern.MonthWithYear) ) gridViewHolder.albumName.setCompoundDrawablesWithIntrinsicBounds( diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListItemBinder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListItemBinder.kt index 929e7d5b1479..aa33ac91b8aa 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListItemBinder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListItemBinder.kt @@ -11,9 +11,9 @@ import android.view.View import androidx.core.content.ContextCompat import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.ui.interfaces.LocalFileListFragmentInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File @@ -80,6 +80,6 @@ internal class LocalFileListItemBinder( holder.fileSize.text = HumanReadableFormatter.formatBytes(file.length()) } - holder.lastModification.text = DisplayUtils.getRelativeTimestamp(activity, file.lastModified()) + holder.lastModification.text = DisplayTextFormatter.formatRelativeTimestamp(activity, file.lastModified()) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index ed41ac446d93..e9c710087e83 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -31,6 +31,7 @@ import com.nextcloud.utils.extensions.isLastResultConflictError import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.sortedByUploadOrder import com.nextcloud.utils.extensions.toFile +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UploadListHeaderBinding @@ -47,7 +48,6 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListAdapterHelper import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.adapter.uploadList.model.UploadListSection import com.owncloud.android.ui.adapter.uploadList.model.UploadListType -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -298,12 +298,10 @@ class UploadListAdapter( holder.binding.uploadDate.setVisibleIf(showDate) if (showDate) { - holder.binding.uploadDate.text = DisplayUtils.getRelativeDateTimeString( + holder.binding.uploadDate.text = DisplayTextFormatter.formatRelativeDateTime( activity, updateTime, - DateUtils.MINUTE_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 + DateUtils.MINUTE_IN_MILLIS ) } } @@ -313,7 +311,7 @@ class UploadListAdapter( holder.binding.uploadAccount.visibility = View.VISIBLE val optionalUser = accountManager.getUser(item.accountName) holder.binding.uploadAccount.text = if (optionalUser.isPresent) { - DisplayUtils.getAccountNameDisplayText(optionalUser.get()) + DisplayTextFormatter.formatAccountName(optionalUser.get()) } else { item.accountName } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt index 9f5f8e4d94ab..d5f1941f61fa 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt @@ -13,12 +13,12 @@ import androidx.annotation.StringRes import com.nextcloud.client.account.User import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.utils.HumanReadableFormatter +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.dialog.conflict.model.ConflictDialogData import com.owncloud.android.ui.dialog.conflict.model.ConflictDialogType import com.owncloud.android.ui.dialog.conflict.model.ConflictFileData -import com.owncloud.android.utils.DisplayUtils import java.io.File object ConflictResolveDialogFactory { @@ -75,7 +75,7 @@ object ConflictResolveDialogFactory { private fun Context.conflictFileData(@StringRes titleId: Int, timestamp: Long, fileLength: Long): ConflictFileData = ConflictFileData( title = getString(titleId), - timestamp = DisplayUtils.getRelativeTimestamp(this, timestamp).toString(), + timestamp = DisplayTextFormatter.formatRelativeTimestamp(this, timestamp).toString(), fileSize = HumanReadableFormatter.formatBytes(fileLength) ) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 734d02d76557..6115a903b305 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -41,6 +41,7 @@ import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; +import com.nextcloud.utils.text.DisplayTextFormatter; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsFragmentBinding; @@ -65,7 +66,6 @@ import com.owncloud.android.ui.events.EventBusFactory; import com.owncloud.android.ui.events.FavoriteEvent; import com.owncloud.android.ui.events.FileDownloadProgressEvent; -import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.EncryptionUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.theme.CapabilityUtils; @@ -673,8 +673,8 @@ private void setFileModificationTimestamp(OCFile file, boolean showDetailedTimes if (showDetailedTimestamp) { binding.lastModificationTimestamp.setText(HumanReadableFormatter.formatDateTime(file.getModificationTimestamp())); } else { - binding.lastModificationTimestamp.setText(DisplayUtils.getRelativeTimestamp(getContext(), - file.getModificationTimestamp())); + binding.lastModificationTimestamp.setText( + DisplayTextFormatter.formatRelativeTimestamp(requireContext(), file.getModificationTimestamp())); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/albums/bottomsheet/AlbumSharingBottomSheet.kt b/app/src/main/java/com/owncloud/android/ui/fragment/albums/bottomsheet/AlbumSharingBottomSheet.kt index 0abc95ceec54..4cdef9b88549 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/albums/bottomsheet/AlbumSharingBottomSheet.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/albums/bottomsheet/AlbumSharingBottomSheet.kt @@ -20,6 +20,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.di.Injectable import com.nextcloud.utils.date.DateFormatPattern import com.nextcloud.utils.extensions.setVisibleIf +import com.nextcloud.utils.text.DisplayTextFormatter import com.nextcloud.utils.thumbnail.ThumbnailArguments import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R @@ -30,7 +31,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.resources.albums.PhotoAlbumEntry import com.owncloud.android.ui.fragment.albums.util.AlbumCollageLayout -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -99,7 +99,7 @@ class AlbumSharingBottomSheet( album.nbItems, album.nbItems ) - albumDate.text = DisplayUtils.getDateByPattern(album.createdDate, DateFormatPattern.MonthWithYear.pattern) + albumDate.text = DisplayTextFormatter.formatDate(album.createdDate, DateFormatPattern.MonthWithYear) } private fun bindAlbumThumbnail(album: PhotoAlbumEntry) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt index 918b39ded320..ad6cb3ce09de 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt @@ -34,6 +34,7 @@ import com.nextcloud.utils.SnackbarUtil import com.nextcloud.utils.extensions.getSerializableArgument import com.nextcloud.utils.extensions.getTypedActivity import com.nextcloud.utils.extensions.setVisibleIf +import com.nextcloud.utils.text.DisplayTextFormatter import com.owncloud.android.R import com.owncloud.android.databinding.BackupFragmentBinding import com.owncloud.android.datamodel.ArbitraryDataProvider @@ -44,7 +45,6 @@ import com.owncloud.android.operations.RefreshFolderOperation import com.owncloud.android.ui.activity.ContactsPreferenceActivity import com.owncloud.android.ui.activity.SettingsActivity import com.owncloud.android.ui.fragment.FileFragment -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.PermissionUtil.checkSelfPermission import com.owncloud.android.utils.theme.ThemeUtils @@ -214,7 +214,7 @@ class BackupFragment : } binding.lastBackupWithDate.text = getString( R.string.last_backup, - DisplayUtils.getRelativeTimestamp(contactsPreferenceActivity, lastBackupTimestamp) + DisplayTextFormatter.formatRelativeTimestamp(contactsPreferenceActivity, lastBackupTimestamp) ) } diff --git a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java index 16e9338d3cda..d06db1b20052 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -29,16 +29,11 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; -import android.text.format.DateUtils; import android.text.style.StyleSpan; import android.util.DisplayMetrics; import android.view.View; -import com.nextcloud.client.account.User; -import com.nextcloud.utils.HumanReadableFormatter; -import com.owncloud.android.MainApp; import com.owncloud.android.R; -import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; @@ -50,10 +45,7 @@ import java.lang.reflect.Method; import java.net.IDN; import java.nio.charset.Charset; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Locale; -import java.util.TimeZone; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -77,10 +69,6 @@ public final class DisplayUtils { private static final String HTTP_PROTOCOL = "http://"; private static final String HTTPS_PROTOCOL = "https://"; private static final String TWITTER_HANDLE_PREFIX = "@"; - private static final int DATE_TIME_PARTS_SIZE = 2; - public static final String MONTH_YEAR_PATTERN = "MMMM yyyy"; - public static final String MONTH_PATTERN = "MMMM"; - public static final String YEAR_PATTERN = "yyyy"; private DisplayUtils() { // utility class -> private constructor @@ -166,78 +154,6 @@ public static String convertIdn(String url, boolean toASCII) { return dots.toString() + urlNoDots.substring(0, hostStart) + host + urlNoDots.substring(hostEnd); } - /** - * Creates the display string for a user. - * - * @return the display string for the given account data - */ - public static String getAccountNameDisplayText(User user) { - final OwnCloudAccount ocs = user.toOwnCloudAccount(); - final String accountName = user.getAccountName(); - return ocs.getDisplayName() - + "@" - + convertIdn(accountName.substring(accountName.lastIndexOf('@') + 1), false); - } - - - /** - * calculates the relative time string based on the given modification timestamp. - * - * @param context the app's context - * @param modificationTimestamp the UNIX timestamp of the file modification time in milliseconds. - * @return a relative time string - */ - public static CharSequence getRelativeTimestamp(Context context, long modificationTimestamp) { - return getRelativeDateTimeString(context, modificationTimestamp, DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, 0); - } - - public static CharSequence getRelativeTimestamp(Context context, long modificationTimestamp, boolean showFuture) { - return getRelativeDateTimeString(context, - modificationTimestamp, - DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - showFuture); - } - - public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, - long transitionResolution, int flags) { - return getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags, false); - } - - public static CharSequence getRelativeDateTimeString(Context c, - long time, - long minResolution, - long transitionResolution, - int flags, - boolean showFuture) { - - - // in Future - if (!showFuture && time > System.currentTimeMillis()) { - return HumanReadableFormatter.formatDateTime(time); - } - // < 60 seconds -> seconds ago - long diff = System.currentTimeMillis() - time; - if (diff > 0 && diff < 60 * 1000 && minResolution == DateUtils.MINUTE_IN_MILLIS) { - return c.getString(R.string.file_list_seconds_ago); - } else { - CharSequence dateString = DateUtils.getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags); - - String[] parts = dateString.toString().split(","); - if (parts.length == DATE_TIME_PARTS_SIZE) { - if (parts[1].contains(":") && !parts[0].contains(":")) { - return parts[0]; - } else if (parts[0].contains(":") && !parts[1].contains(":")) { - return parts[1]; - } - } - // dateString contains unexpected format. fallback: use relative date time string from android api as is. - return dateString.toString(); - } - } - /** * Gets the screen size in pixels. * @@ -358,19 +274,4 @@ static public void openSortingOrderDialogFragment(FragmentManager supportFragmen default -> R.string.menu_item_sort_by_name_a_z; }; } - - public static String getDateByPattern(long timestamp, String pattern) { - return getDateByPattern(timestamp, null, pattern); - } - - public static String getDateByPattern(long timestamp, @Nullable Context context, String pattern) { - DateFormat df; - if (context == null) { - context = MainApp.getAppContext(); - } - df = new SimpleDateFormat(pattern, context.getResources().getConfiguration().locale); - df.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID())); - - return df.format(timestamp); - } }