ganfra
2 years ago
7 changed files with 219 additions and 87 deletions
@ -0,0 +1,21 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.dateformatter |
||||||
|
|
||||||
|
interface DaySeparatorFormatter { |
||||||
|
fun format(timestamp: Long): String |
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.dateformatter.impl |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.text.format.DateFormat |
||||||
|
import android.text.format.DateUtils |
||||||
|
import io.element.android.libraries.di.ApplicationContext |
||||||
|
import kotlinx.datetime.Clock |
||||||
|
import kotlinx.datetime.LocalDateTime |
||||||
|
import kotlinx.datetime.TimeZone |
||||||
|
import kotlinx.datetime.toInstant |
||||||
|
import kotlinx.datetime.toJavaLocalDate |
||||||
|
import kotlinx.datetime.toJavaLocalDateTime |
||||||
|
import java.time.Period |
||||||
|
import java.time.format.DateTimeFormatter |
||||||
|
import java.util.Locale |
||||||
|
import javax.inject.Inject |
||||||
|
import kotlin.math.absoluteValue |
||||||
|
|
||||||
|
class DateFormatters @Inject constructor( |
||||||
|
@ApplicationContext private val context: Context, |
||||||
|
private val locale: Locale, |
||||||
|
private val clock: Clock, |
||||||
|
private val timeZone: TimeZone, |
||||||
|
) { |
||||||
|
|
||||||
|
private val hourFormatter by lazy { |
||||||
|
if (DateFormat.is24HourFormat(context)) { |
||||||
|
DateTimeFormatter.ofPattern("HH:mm", locale) |
||||||
|
} else { |
||||||
|
DateTimeFormatter.ofPattern("h:mm a", locale) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private val fullDateFormatter by lazy { |
||||||
|
val pattern = if (DateFormat.is24HourFormat(context)) { |
||||||
|
DateFormat.getBestDateTimePattern(locale, "EEE, d MMM yyyy HH:mm") |
||||||
|
} else { |
||||||
|
DateFormat.getBestDateTimePattern(locale, "EEE, d MMM yyyy h:mm a") |
||||||
|
} |
||||||
|
DateTimeFormatter.ofPattern(pattern, locale) |
||||||
|
} |
||||||
|
|
||||||
|
private val dateWithMonthFormatter: DateTimeFormatter by lazy { |
||||||
|
val pattern = DateFormat.getBestDateTimePattern(locale, "d MMM") |
||||||
|
DateTimeFormatter.ofPattern(pattern) |
||||||
|
} |
||||||
|
|
||||||
|
private val dateWithYearFormatter: DateTimeFormatter by lazy { |
||||||
|
val pattern = DateFormat.getBestDateTimePattern(locale, "d MMM y") |
||||||
|
DateTimeFormatter.ofPattern(pattern) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun formatFullDate(localDateTime: LocalDateTime): String { |
||||||
|
return fullDateFormatter.format(localDateTime.toJavaLocalDateTime()) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun formatHour(localDateTime: LocalDateTime): String { |
||||||
|
return hourFormatter.format(localDateTime.toJavaLocalDateTime()) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun formatDateWithMonth(localDateTime: LocalDateTime): String { |
||||||
|
return dateWithMonthFormatter.format(localDateTime.toJavaLocalDateTime()) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun formatDateWithYear(localDateTime: LocalDateTime): String { |
||||||
|
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime()) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun formatDate( |
||||||
|
dateToFormat: LocalDateTime, |
||||||
|
currentDate: LocalDateTime, |
||||||
|
useRelative: Boolean |
||||||
|
): String { |
||||||
|
val period = Period.between(dateToFormat.date.toJavaLocalDate(), currentDate.date.toJavaLocalDate()) |
||||||
|
return if (period.years.absoluteValue >= 1) { |
||||||
|
formatDateWithYear(dateToFormat) |
||||||
|
} else if (useRelative && period.days.absoluteValue < 2 && period.months.absoluteValue < 1) { |
||||||
|
getRelativeDay(dateToFormat.toInstant(timeZone).toEpochMilliseconds()) |
||||||
|
} else { |
||||||
|
formatDateWithMonth(dateToFormat) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun getRelativeDay(ts: Long): String { |
||||||
|
return DateUtils.getRelativeTimeSpanString( |
||||||
|
ts, |
||||||
|
clock.now().toEpochMilliseconds(), |
||||||
|
DateUtils.DAY_IN_MILLIS, |
||||||
|
DateUtils.FORMAT_SHOW_WEEKDAY |
||||||
|
).toString() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.dateformatter.impl |
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding |
||||||
|
import io.element.android.libraries.dateformatter.DaySeparatorFormatter |
||||||
|
import io.element.android.libraries.di.AppScope |
||||||
|
import javax.inject.Inject |
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class) |
||||||
|
class DefaultDaySeparatorFormatter @Inject constructor( |
||||||
|
private val localDateTimeProvider: LocalDateTimeProvider, |
||||||
|
private val dateFormatters: DateFormatters, |
||||||
|
) : DaySeparatorFormatter { |
||||||
|
|
||||||
|
override fun format(timestamp: Long): String { |
||||||
|
val dateToFormat = localDateTimeProvider.providesFromTimestamp(timestamp) |
||||||
|
return dateFormatters.formatDateWithYear(dateToFormat) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.libraries.dateformatter.impl |
||||||
|
|
||||||
|
import kotlinx.datetime.Clock |
||||||
|
import kotlinx.datetime.Instant |
||||||
|
import kotlinx.datetime.LocalDateTime |
||||||
|
import kotlinx.datetime.TimeZone |
||||||
|
import kotlinx.datetime.toLocalDateTime |
||||||
|
import javax.inject.Inject |
||||||
|
|
||||||
|
class LocalDateTimeProvider @Inject constructor( |
||||||
|
private val clock: Clock, |
||||||
|
private val timezone: TimeZone, |
||||||
|
) { |
||||||
|
|
||||||
|
fun providesNow(): LocalDateTime { |
||||||
|
val now: Instant = clock.now() |
||||||
|
return now.toLocalDateTime(timezone) |
||||||
|
} |
||||||
|
|
||||||
|
fun providesFromTimestamp(timestamp: Long): LocalDateTime { |
||||||
|
val tsInstant = Instant.fromEpochMilliseconds(timestamp) |
||||||
|
return tsInstant.toLocalDateTime(timezone) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue