chore: support localization in most DateTime conversions

This commit is contained in:
Jagandeep Brar
2022-06-17 01:20:25 -04:00
parent 8b5745044e
commit 9c6016edc9
50 changed files with 248 additions and 164 deletions

View File

@@ -71,13 +71,23 @@
"lunasea.MinutesAgo": "{} Minutes Ago",
"lunasea.Module": "Module",
"lunasea.ModuleIsNotEnabled": "{} Is Not Enabled",
"lunasea.Months": "{} Months",
"lunasea.MonthsAgo": "{} Months Ago",
"lunasea.New": "New",
"lunasea.NotSet": "Not Set",
"lunasea.NoModulesEnabled": "No Modules Enabled",
"lunasea.OneDay": "1 Day",
"lunasea.OneDayAgo": "1 Day Ago",
"lunasea.OneHour": "1 Hour",
"lunasea.OneHourAgo": "1 Hour Ago",
"lunasea.OneMinute": "1 Minute",
"lunasea.OneMinuteAgo": "1 Minute Ago",
"lunasea.OneMonth": "1 Month",
"lunasea.OneMonthAgo": "1 Month Ago",
"lunasea.OneSecond": "1 Second",
"lunasea.OneSecondAgo": "1 Second Ago",
"lunasea.OneYear": "1 Year",
"lunasea.OneYearAgo": "1 Year Ago",
"lunasea.Options": "Options",
"lunasea.Page": "Page",
"lunasea.PlatformSpecific": "Platform-Specific",
@@ -97,6 +107,7 @@
"lunasea.Settings": "Settings",
"lunasea.Stable": "Stable",
"lunasea.StartingView": "Starting View",
"lunasea.Today": "Today",
"lunasea.TransactionFailure": "Transaction Failure",
"lunasea.TryAgain": "Try Again",
"lunasea.Tweaks": "Tweaks",
@@ -109,6 +120,8 @@
"lunasea.View": "View",
"lunasea.Warning": "Warning",
"lunasea.Website": "Website",
"lunasea.Years": "{} Years",
"lunasea.YearsAgo": "{} Years Ago",
"overseerr.Audio": "Audio",
"overseerr.Approved": "Approved",
"overseerr.Available": "Available",

View File

@@ -1,7 +1,6 @@
/// This file is deprecated and should no longer be actively used.
/// All imports should happen directly and canonical export files will not be used anymore.
export 'deprecated/extensions/datetime.dart';
export 'deprecated/state/module_state.dart';
export 'deprecated/state/state.dart';
export 'deprecated/router/module_router.dart';

View File

@@ -1,74 +0,0 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/string/string.dart';
extension DateTimeExtension on DateTime {
/// Returns a string representation of the "age" of the [DateTime] object.
///
/// Compares to [DateTime.now().toLocal()] to calculate the age.
String get lunaAge {
Duration diff = DateTime.now().toLocal().difference(this);
if (diff.inSeconds < 10) return 'Just Now';
if (diff.inDays >= 1) return '${this.lunaDaysDifference} Ago';
if (diff.inHours >= 1)
return '${diff.inHours} ${diff.inHours == 1 ? 'Hour' : 'Hours'} Ago';
if (diff.inMinutes >= 1)
return '${diff.inMinutes} ${diff.inMinutes == 1 ? 'Minute' : 'Minutes'} Ago';
return '${diff.inSeconds} ${diff.inSeconds == 1 ? 'Second' : 'Seconds'} Ago';
}
/// Returns a string representation of the difference in days/months/years.
///
/// Compares to [DateTime.now()] to calculate the difference.
String get lunaDaysDifference {
Duration diff = this.difference(DateTime.now());
int absoluteDays = diff.inDays.abs();
if (absoluteDays == 0) return 'Today';
// If greater than 2 years, show in years
if (absoluteDays >= 365 * 2) return '${(absoluteDays / 365).round()} Years';
// If greater than 3 months, show in months
if (absoluteDays >= 30 * 3) return '${(absoluteDays / 30).round()} Months';
return '$absoluteDays ${absoluteDays == 1 ? "Day" : "Days"}';
}
/// Returns just the time as a string.
///
/// 3 PM will return either 15:00 (24 hour style) or 3:00 PM depending on the configured database option.
String get lunaTime => LunaSeaDatabase.USE_24_HOUR_TIME.read()
? DateFormat.Hm().format(this)
: DateFormat.jm().format(this);
/// Returns just the date as a string.
///
/// Formatted as YYYY-MM-DD
String get lunaDate =>
'${this.year.toString().padLeft(4, '0')}-${this.month.toString().padLeft(2, '0')}-${this.day.toString().padLeft(2, '0')}';
/// Returns the date as a string.
///
/// Formatted as "<month name> <day>, <year>".
String lunaDateReadable({
bool shortMonth = false,
}) {
return DateFormat(shortMonth ? 'MMM dd, y' : 'MMMM dd, y')
.format(this.toLocal());
}
/// Returns the date and time as a string.
///
/// Formatted as `<month name> <day>, <year> • <hour>:<minute>:<second>`.
///
/// Set `timeOnNewLine` to true to have the time returned on a new line instead of separated by a bullet.
String lunaDateTimeReadable({
bool timeOnNewLine = false,
bool showSeconds = true,
String sameLineDelimiter = LunaUI.TEXT_BULLET,
bool shortMonth = false,
}) {
String _format = shortMonth ? 'MMM dd, y' : 'MMMM dd, y';
_format += timeOnNewLine ? '\n' : sameLineDelimiter.pad();
_format += LunaSeaDatabase.USE_24_HOUR_TIME.read() ? 'HH:mm' : 'hh:mm';
_format += showSeconds ? ':ss' : '';
_format += LunaSeaDatabase.USE_24_HOUR_TIME.read() ? '' : ' a';
return DateFormat(_format).format(this.toLocal());
}
}

View File

@@ -1,5 +1,97 @@
import 'package:lunasea/database/tables/lunasea.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/system/localization.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
extension DateTimeExtension on DateTime {
String _formatted(String format) {
final locale = LunaLanguage.current.languageTag;
return DateFormat(format, locale).format(this.toLocal());
}
DateTime floor() {
return DateTime(this.year, this.month, this.day);
}
String asTimeOnly() {
if (LunaSeaDatabase.USE_24_HOUR_TIME.read()) return _formatted('Hm');
return _formatted('jm');
}
String asDateOnly({
shortenMonth = false,
}) {
final format = shortenMonth ? 'MMM dd, y' : 'MMMM dd, y';
return _formatted(format);
}
String asDateTime({
bool showSeconds = true,
bool shortenMonth = false,
String? delimiter,
}) {
final format = StringBuffer(shortenMonth ? 'MMM dd, y' : 'MMMM dd, y');
format.write(delimiter ?? LunaUI.TEXT_BULLET.pad());
format.write(LunaSeaDatabase.USE_24_HOUR_TIME.read() ? 'HH:mm' : 'hh:mm');
if (showSeconds) format.write(':ss');
if (!LunaSeaDatabase.USE_24_HOUR_TIME.read()) format.write(' a');
return _formatted(format.toString());
}
String asPoleDate() {
final year = this.year.toString().padLeft(4, '0');
final month = this.month.toString().padLeft(2, '0');
final day = this.day.toString().padLeft(2, '0');
return '$year-$month-$day';
}
String asAge() {
final diff = DateTime.now().difference(this);
if (diff.inSeconds < 15) return 'lunasea.JustNow'.tr();
final days = diff.inDays.abs();
if (days >= 1) {
final years = (days / 365).floor();
if (years == 1) return 'lunasea.OneYearAgo'.tr();
if (years > 1) return 'lunasea.YearsAgo'.tr(args: [years.toString()]);
final months = (days / 30).floor();
if (months == 1) return 'lunasea.OneMonthAgo'.tr();
if (months > 1) return 'lunasea.MonthsAgo'.tr(args: [months.toString()]);
if (days == 1) return 'lunasea.OneDayAgo'.tr();
if (days > 1) return 'lunasea.DaysAgo'.tr(args: [days.toString()]);
}
final hours = diff.inHours.abs();
if (hours == 1) return 'lunasea.OneHourAgo'.tr();
if (hours > 1) return 'lunasea.HoursAgo'.tr(args: [hours.toString()]);
final mins = diff.inMinutes.abs();
if (mins == 1) return 'lunasea.OneMinuteAgo'.tr();
if (mins > 1) return 'lunasea.MinutesAgo'.tr(args: [mins.toString()]);
final secs = diff.inSeconds.abs();
if (secs == 1) return 'lunasea.OneSecondAgo'.tr();
return 'lunasea.SecondsAgo'.tr(args: [secs.toString()]);
}
String asDaysDifference() {
final diff = DateTime.now().difference(this);
final days = diff.inDays.abs();
if (days == 0) return 'lunasea.Today'.tr();
final years = (days / 365).floor();
if (years == 1) return 'lunasea.OneYear'.tr();
if (years > 1) return 'lunasea.Years'.tr(args: [years.toString()]);
final months = (days / 30).floor();
if (months == 1) return 'lunasea.OneMonth'.tr();
if (months > 1) return 'lunasea.Months'.tr(args: [months.toString()]);
if (days == 1) return 'lunasea.OneDay'.tr();
return 'lunasea.Days'.tr(args: [days.toString()]);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
extension DurationAsTimestampExtension on Duration? {

View File

@@ -1,4 +1,5 @@
import 'package:flutter/services.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
extension StringNullableExtension on String? {

View File

@@ -104,21 +104,34 @@ class _State extends State<LunaOS> {
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
_boot();
_healthCheck();
});
SchedulerBinding.instance.addPostFrameCallback(_boot);
}
Future<void> _boot(Duration duration) async {
_initLocale();
_initNotifications();
if (LunaQuickActions.isSupported) LunaQuickActions().initialize();
_healthCheck();
}
Future<void> _initNotifications() async {
final messaging = LunaFirebaseMessaging();
final firestore = LunaFirebaseFirestore();
await messaging.requestNotificationPermissions();
if (LunaFirebaseMessaging.isSupported) {
final messaging = LunaFirebaseMessaging();
final firestore = LunaFirebaseFirestore();
await messaging.requestNotificationPermissions();
firestore.addDeviceToken();
messaging.checkAndHandleInitialMessage();
messaging.registerOnMessageListener();
messaging.registerOnMessageOpenedAppListener();
firestore.addDeviceToken();
messaging.checkAndHandleInitialMessage();
messaging.registerOnMessageListener();
messaging.registerOnMessageOpenedAppListener();
}
}
void _initLocale() {
final lan = LunaLanguage.fromLocale(context.locale) ?? LunaLanguage.ENGLISH;
context.setLocale(lan.locale);
Intl.defaultLocale = lan.languageTag;
}
Future<void> _healthCheck() async {
@@ -129,16 +142,6 @@ class _State extends State<LunaOS> {
}
}
Future<void> _boot() async {
if (LunaFirebaseMessaging.isSupported) _initNotifications();
String? tag = LunaLanguage.ENGLISH.fromLocale(context.locale)?.languageTag;
tag ??= LunaLanguage.ENGLISH.languageTag;
Intl.defaultLocale = tag;
if (LunaQuickActions.isSupported) LunaQuickActions().initialize();
}
@override
Widget build(BuildContext context) => HomeRouter().widget();
}

View File

@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:lunasea/modules.dart';
import 'package:lunasea/database/models/profile.dart';
import 'package:lunasea/database/tables/lunasea.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
import 'package:lunasea/modules/wake_on_lan/api/wake_on_lan.dart';
import 'package:lunasea/modules/dashboard/routes/dashboard/widgets/navigation_bar.dart';

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:lunasea/database/tables/dashboard.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/vendor.dart';
import 'package:provider/provider.dart';
import 'package:lunasea/widgets/ui.dart';

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
class NZBGetHistoryData {
@@ -52,7 +53,7 @@ class NZBGetHistoryData {
}
String get completeTime {
return timestampObject?.lunaAge ?? 'Unknown';
return timestampObject?.asAge() ?? 'Unknown';
}
String get healthString {

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/double/time.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -152,7 +153,7 @@ extension LunaRadarrEventType on RadarrEventType {
title: 'published date',
body: DateTime.tryParse(record.data!['publishedDate']) != null
? DateTime.tryParse(record.data!['publishedDate'])
?.lunaDateTimeReadable(timeOnNewLine: true) ??
?.asDateTime(delimiter: '\n') ??
LunaUI.TEXT_EMDASH
: LunaUI.TEXT_EMDASH,
),

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/extensions/int/duration.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -39,8 +40,7 @@ extension LunaRadarrMovieExtension on RadarrMovie {
}
String lunaDateAdded([bool short = false]) {
if (this.added != null)
return this.added!.lunaDateReadable(shortMonth: short);
if (this.added != null) return this.added!.asDateOnly(shortenMonth: short);
return LunaUI.TEXT_EMDASH;
}
@@ -52,25 +52,25 @@ extension LunaRadarrMovieExtension on RadarrMovie {
String lunaInCinemasOn([bool short = false]) {
if (this.inCinemas != null)
return this.inCinemas!.lunaDateReadable(shortMonth: short);
return this.inCinemas!.asDateOnly(shortenMonth: short);
return LunaUI.TEXT_EMDASH;
}
String lunaPhysicalReleaseDate([bool short = false]) {
if (this.physicalRelease != null)
return this.physicalRelease!.lunaDateReadable(shortMonth: short);
return this.physicalRelease!.asDateOnly(shortenMonth: short);
return LunaUI.TEXT_EMDASH;
}
String lunaDigitalReleaseDate([bool short = false]) {
if (this.digitalRelease != null)
return this.digitalRelease!.lunaDateReadable(shortMonth: short);
return this.digitalRelease!.asDateOnly(shortenMonth: short);
return LunaUI.TEXT_EMDASH;
}
String get lunaReleaseDate {
if (this.lunaEarlierReleaseDate != null)
return this.lunaEarlierReleaseDate!.lunaDateReadable();
return this.lunaEarlierReleaseDate!.asDateOnly();
return LunaUI.TEXT_EMDASH;
}
@@ -122,7 +122,7 @@ extension LunaRadarrMovieExtension on RadarrMovie {
);
// In Cinemas
if (this.inCinemas != null && this.inCinemas!.toLocal().isAfter(now)) {
String _date = this.inCinemas!.lunaDaysDifference.toUpperCase();
String _date = this.inCinemas!.asDaysDifference().toUpperCase();
return Text(
_date == 'TODAY' ? _date : 'IN $_date',
style: const TextStyle(
@@ -135,7 +135,7 @@ extension LunaRadarrMovieExtension on RadarrMovie {
DateTime? _release = lunaEarlierReleaseDate;
// Releases
if (_release != null) {
String _date = _release.lunaDaysDifference.toUpperCase();
String _date = _release.asDaysDifference().toUpperCase();
return Text(
_date == 'TODAY' ? _date : 'IN $_date',
style: const TextStyle(

View File

@@ -1,4 +1,5 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -26,7 +27,7 @@ extension LunaRadarrMovieFileExtension on RadarrMovieFile {
String get lunaDateAdded {
if (this.dateAdded != null)
return this.dateAdded!.lunaDateTimeReadable(timeOnNewLine: true);
return this.dateAdded!.asDateTime(delimiter: '\n');
return LunaUI.TEXT_EMDASH;
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -23,8 +24,8 @@ class RadarrHistoryTile extends StatelessWidget {
collapsedSubtitles: [
TextSpan(
text: [
history.date?.lunaAge ?? LunaUI.TEXT_EMDASH,
history.date?.lunaDateTimeReadable() ?? LunaUI.TEXT_EMDASH,
history.date?.asAge() ?? LunaUI.TEXT_EMDASH,
history.date?.asDateTime() ?? LunaUI.TEXT_EMDASH,
].join(LunaUI.TEXT_BULLET.pad()),
),
TextSpan(

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -68,7 +69,7 @@ class _State extends State<RadarrMissingTile> {
}
TextSpan _subtitle3() {
String? _days = widget.movie.lunaEarlierReleaseDate?.lunaDaysDifference;
String? _days = widget.movie.lunaEarlierReleaseDate?.asDaysDifference();
return TextSpan(
style: const TextStyle(
fontWeight: LunaUI.FONT_WEIGHT_BOLD,

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/radarr.dart';
@@ -76,11 +77,11 @@ class _State extends State<RadarrUpcomingTile> {
String type;
if (widget.movie.lunaIsInCinemas && !widget.movie.lunaIsReleased) {
color = LunaColours.blue;
_days = widget.movie.lunaEarlierReleaseDate?.lunaDaysDifference;
_days = widget.movie.lunaEarlierReleaseDate?.asDaysDifference();
type = 'release';
} else if (!widget.movie.lunaIsInCinemas && !widget.movie.lunaIsReleased) {
color = LunaColours.orange;
_days = widget.movie.inCinemas?.lunaDaysDifference;
_days = widget.movie.inCinemas?.asDaysDifference();
type = 'cinema';
} else {
color = LunaColours.grey;

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
class SABnzbdHistoryData {
@@ -35,7 +36,7 @@ class SABnzbdHistoryData {
}
String get completeTimeString {
return completeTimeObject.lunaAge;
return completeTimeObject.asAge();
}
String get sizeReadable {

View File

@@ -1,4 +1,5 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
class NewznabResultData {
String title;
@@ -32,7 +33,7 @@ class NewznabResultData {
return null;
}
String get age => dateObject?.lunaAge ?? 'lunasea.Unknown'.tr();
String get age => dateObject?.asAge() ?? 'lunasea.Unknown'.tr();
int get posix => dateObject?.millisecondsSinceEpoch ?? 0;
}

View File

@@ -1,7 +1,6 @@
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/database/tables/dashboard.dart';
import 'package:tuple/tuple.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/modules.dart';
import 'package:lunasea/widgets/ui.dart';

View File

@@ -51,17 +51,17 @@ class _State extends State<_Widget> with LunaScrollControllerMixin {
}
Widget _language() {
String? _language = LunaLanguage.ENGLISH.fromLocale(context.locale)?.name;
String? _language = LunaLanguage.fromLocale(context.locale)?.name;
return LunaBlock(
title: 'settings.Language'.tr(),
body: [TextSpan(text: _language ?? LunaUI.TEXT_EMDASH)],
trailing: const LunaIconButton(icon: Icons.language_rounded),
onTap: () async {
Tuple2<bool, LunaLanguage?> result =
await SettingsDialogs().changeLanguage(context);
final result = await SettingsDialogs().changeLanguage(context);
if (result.item1) {
result.item2!.use(context);
Intl.defaultLocale = result.item2!.languageTag;
context.setLocale(result.item2!.locale);
// Intl.defaultLocale = result.item2!.languageTag;
}
},
);

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/database/models/log.dart';
import 'package:lunasea/extensions/datetime.dart';
class SettingsSystemLogTile extends StatelessWidget {
final LunaLog log;
@@ -12,8 +13,8 @@ class SettingsSystemLogTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
String dateTime = DateTime.fromMillisecondsSinceEpoch(log.timestamp)
.lunaDateTimeReadable();
String dateTime =
DateTime.fromMillisecondsSinceEpoch(log.timestamp).asDateTime();
return LunaExpandableListTile(
title: log.message,
collapsedSubtitles: [

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/double/time.dart';
import 'package:lunasea/modules/sonarr.dart';
@@ -273,7 +274,7 @@ extension SonarrEventTypeLunaExtension on SonarrEventType {
LunaTableContent(
title: 'sonarr.PublishedDate'.tr(),
body: DateTime.tryParse(history.data!['publishedDate'])
?.lunaDateTimeReadable(timeOnNewLine: true)),
?.asDateTime(delimiter: '\n')),
];
}

View File

@@ -1,4 +1,5 @@
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/extensions/int/duration.dart';
import 'package:lunasea/extensions/string/string.dart';
@@ -40,21 +41,19 @@ extension SonarrSeriesExtension on SonarrSeries {
String lunaNextAiring([bool short = false]) {
if (this.status == 'ended') return 'sonarr.SeriesEnded'.tr();
if (this.nextAiring == null) return 'lunasea.Unknown'.tr();
return this.nextAiring!.lunaDateTimeReadable(
timeOnNewLine: false,
return this.nextAiring!.asDateTime(
showSeconds: false,
sameLineDelimiter: '@',
shortMonth: short,
delimiter: '@'.pad(),
shortenMonth: short,
);
}
String lunaPreviousAiring([bool short = false]) {
if (this.previousAiring == null) return LunaUI.TEXT_EMDASH;
return this.previousAiring!.lunaDateTimeReadable(
timeOnNewLine: false,
return this.previousAiring!.asDateTime(
showSeconds: false,
sameLineDelimiter: '@',
shortMonth: short,
delimiter: '@'.pad(),
shortenMonth: short,
);
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/sonarr.dart';
@@ -145,8 +146,8 @@ class SonarrHistoryTile extends StatelessWidget {
TextSpan _subtitle2() {
return TextSpan(
text: [
history.date?.lunaAge ?? LunaUI.TEXT_EMDASH,
history.date?.lunaDateTimeReadable() ?? LunaUI.TEXT_EMDASH,
history.date?.asAge() ?? LunaUI.TEXT_EMDASH,
history.date?.asDateTime() ?? LunaUI.TEXT_EMDASH,
].join(LunaUI.TEXT_BULLET.pad()),
);
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/sonarr.dart';
@@ -85,7 +86,7 @@ class _State extends State<SonarrMissingTile> {
TextSpan(
text: widget.record.airDateUtc == null
? 'Aired'
: 'Aired ${widget.record.airDateUtc!.toLocal().lunaAge}'),
: 'Aired ${widget.record.airDateUtc!.toLocal().asAge()}'),
],
);
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/sonarr.dart';
@@ -141,8 +142,7 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet {
),
LunaTableContent(
title: 'sonarr.AddedOn'.tr(),
body: episodeFile?.dateAdded
?.lunaDateTimeReadable(timeOnNewLine: true),
body: episodeFile?.dateAdded?.asDateTime(delimiter: '\n'),
),
],
buttons: [

View File

@@ -1,7 +1,9 @@
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/sonarr.dart';
class SonarrSeriesDetailsSeasonTile extends StatefulWidget {
@@ -62,10 +64,9 @@ class _State extends State<SonarrSeriesDetailsSeasonTile> {
TextSpan _subtitle1() {
return TextSpan(
text: widget.season.statistics?.previousAiring?.lunaDateTimeReadable(
timeOnNewLine: false,
text: widget.season.statistics?.previousAiring?.asDateTime(
showSeconds: false,
sameLineDelimiter: '@',
delimiter: '@'.pad(),
) ??
LunaUI.TEXT_EMDASH,
);

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
extension TautulliHistoryRecordExtension on TautulliHistoryRecord {
@@ -32,7 +32,7 @@ extension TautulliHistoryRecordExtension on TautulliHistoryRecord {
}
}
String get lsDate => this.date?.lunaAge ?? 'Unknown';
String get lsDate => this.date?.asAge() ?? 'Unknown';
String get lsStatus {
switch (this.watchedStatus) {

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/extensions/int/bytes.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -218,7 +219,7 @@ extension TautulliSessionExtension on TautulliSession {
Duration _progress = Duration(
seconds: (this.streamDuration!.inSeconds * _percent).floor());
Duration _eta = this.streamDuration! - _progress;
return DateTime.now().add(_eta).lunaTime;
return DateTime.now().add(_eta).asTimeOnly();
} catch (error, stack) {
LunaLogger().error('Failed to calculate ETA', error, stack);
return 'lunasea.Unknown'.tr();

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -47,11 +48,11 @@ class TautulliHistoryDetailsInformation extends StatelessWidget {
LunaTableContent(
title: 'date',
body: DateFormat('yyyy-MM-dd').format(history.date!)),
LunaTableContent(title: 'started', body: history.date!.lunaTime),
LunaTableContent(title: 'started', body: history.date!.asTimeOnly()),
LunaTableContent(
title: 'stopped',
body: history.state == null
? history.stopped!.lunaTime
? history.stopped!.asTimeOnly()
: LunaUI.TEXT_EMDASH),
LunaTableContent(
title: 'paused', body: history.pausedCounter!.asWordsTimestamp()),

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -31,7 +32,7 @@ class TautulliLibrariesLibraryTile extends StatelessWidget {
color: LunaColours.accent,
fontWeight: LunaUI.FONT_WEIGHT_BOLD,
),
text: library.lastAccessed?.lunaAge ?? 'Unknown',
text: library.lastAccessed?.asAge() ?? 'Unknown',
),
],
backgroundUrl:

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliLibrariesDetailsInformationDetails extends StatelessWidget {
@@ -32,7 +33,7 @@ class TautulliLibrariesDetailsInformationDetails extends StatelessWidget {
title: 'last played',
body: [
library.lastPlayed ?? LunaUI.TEXT_EMDASH,
library.lastAccessed?.lunaAge ?? 'Unknown',
library.lastAccessed?.asAge() ?? 'Unknown',
].join('\n'),
),
],

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliLogsLoginsLogTile extends StatelessWidget {
@@ -25,7 +26,7 @@ class TautulliLogsLoginsLogTile extends StatelessWidget {
TextSpan(text: '${login.os}\n'),
TextSpan(text: '${login.host}\n'),
TextSpan(
text: login.timestamp!.lunaDateTimeReadable(),
text: login.timestamp!.asDateTime(),
style: const TextStyle(
color: LunaColours.accent,
fontWeight: LunaUI.FONT_WEIGHT_BOLD,

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliLogsNewsletterLogTile extends StatelessWidget {
@@ -25,7 +26,7 @@ class TautulliLogsNewsletterLogTile extends StatelessWidget {
TextSpan(text: newsletter.subjectText),
TextSpan(text: newsletter.bodyText),
TextSpan(
text: newsletter.timestamp!.lunaDateTimeReadable(),
text: newsletter.timestamp!.asDateTime(),
style: const TextStyle(
color: LunaColours.accent,
fontWeight: LunaUI.FONT_WEIGHT_BOLD,

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliLogsNotificationLogTile extends StatelessWidget {
@@ -25,7 +26,7 @@ class TautulliLogsNotificationLogTile extends StatelessWidget {
TextSpan(text: notification.subjectText),
TextSpan(text: notification.bodyText),
TextSpan(
text: notification.timestamp!.lunaDateTimeReadable(),
text: notification.timestamp!.asDateTime(),
style: const TextStyle(
color: LunaColours.accent,
fontWeight: LunaUI.FONT_WEIGHT_BOLD,

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -24,7 +25,7 @@ class TautulliMediaDetailsMetadataMetadata extends StatelessWidget {
if (metadata!.addedAt != null)
LunaTableContent(
title: 'added',
body: metadata!.addedAt!.lunaDate,
body: metadata!.addedAt!.asPoleDate(),
),
if (metadata!.duration != null)
LunaTableContent(

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -110,7 +111,7 @@ class _State extends State<TautulliRecentlyAddedContentTile> {
const TextSpan(text: LunaUI.TEXT_EMDASH),
TextSpan(text: widget.recentlyAdded.libraryName),
TextSpan(
text: widget.recentlyAdded.addedAt?.lunaAge ?? 'lunasea.Unknown'.tr(),
text: widget.recentlyAdded.addedAt?.asAge() ?? 'lunasea.Unknown'.tr(),
),
];
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -70,7 +71,7 @@ class _State extends State<TautulliStatisticsMediaTile> {
widget.data['last_play'] != null
? TextSpan(
text:
'Last Played ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_play'] * 1000).lunaAge}',
'Last Played ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_play'] * 1000).asAge()}',
)
: const TextSpan(text: LunaUI.TEXT_EMDASH)
];

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliStatisticsRecentlyWatchedTile extends StatefulWidget {
@@ -41,7 +42,7 @@ class _State extends State<TautulliStatisticsRecentlyWatchedTile> {
widget.data['last_watch'] != null
? TextSpan(
text:
'Watched ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_watch'] * 1000).lunaAge}',
'Watched ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_watch'] * 1000).asAge()}',
)
: const TextSpan(text: LunaUI.TEXT_EMDASH)
];

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -72,7 +73,7 @@ class _State extends State<TautulliStatisticsUserTile> {
widget.data['last_play'] != null
? TextSpan(
text:
'Last Streamed ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_play'] * 1000).lunaAge}',
'Last Streamed ${DateTime.fromMillisecondsSinceEpoch(widget.data['last_play'] * 1000).asAge()}',
)
: const TextSpan(text: LunaUI.TEXT_EMDASH)
];

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/modules/tautulli.dart';
class TautulliUserTile extends StatelessWidget {
@@ -24,7 +25,7 @@ class TautulliUserTile extends StatelessWidget {
),
backgroundHeaders: context.read<TautulliState>().headers,
body: [
TextSpan(text: user.lastSeen?.lunaAge ?? 'Never'),
TextSpan(text: user.lastSeen?.asAge() ?? 'Never'),
TextSpan(text: user.lastPlayed ?? 'Never'),
],
bodyLeadingIcons: const [

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/string/string.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -92,7 +93,7 @@ class _State extends State<TautulliUserDetailsIPAddresses>
body: [
TextSpan(
children: [
TextSpan(text: record.lastSeen?.lunaAge ?? 'lunasea.Unknown'.tr()),
TextSpan(text: record.lastSeen?.asAge() ?? 'lunasea.Unknown'.tr()),
TextSpan(text: LunaUI.TEXT_BULLET.pad()),
TextSpan(text: _count == 1 ? '1 Play' : '$_count Plays'),
],

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/extensions/datetime.dart';
import 'package:lunasea/extensions/duration/timestamp.dart';
import 'package:lunasea/modules/tautulli.dart';
@@ -130,7 +131,7 @@ class _State extends State<TautulliUserDetailsProfile>
LunaTableContent(
title: 'last seen',
body: widget.user.lastSeen != null
? widget.user.lastSeen?.lunaAge ?? 'Unknown'
? widget.user.lastSeen?.asAge() ?? 'Unknown'
: 'Never',
),
LunaTableContent(title: '', body: ''),

View File

@@ -1,4 +1,5 @@
import 'package:lunasea/database/models/profile.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
import 'package:lunasea/system/logger.dart';
import 'package:wake_on_lan/wake_on_lan.dart';

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/vendor.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/system/environment.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
const FLAVOR_EDGE = 'edge';

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:lunasea/deprecated/state/state.dart';
import 'package:lunasea/system/flavor.dart';
import 'package:lunasea/vendor.dart';
@@ -34,11 +35,14 @@ enum LunaLanguage {
SPANISH,
SWEDISH,
TURKISH,
VIETNAMESE,
}
VIETNAMESE;
extension LunaLanguageExtension on LunaLanguage {
LunaLanguage? fromLocale(Locale locale) {
static LunaLanguage get current {
final locale = LunaState.navigatorKey.currentContext!.locale;
return fromLocale(locale) ?? LunaLanguage.ENGLISH;
}
static LunaLanguage? fromLocale(Locale locale) {
if (locale.toLanguageTag() == LunaLanguage.CHINESE_SIMPLIFIED.languageTag)
return LunaLanguage.CHINESE_SIMPLIFIED;
if (locale.toLanguageTag() == LunaLanguage.DUTCH.languageTag)
@@ -69,7 +73,9 @@ extension LunaLanguageExtension on LunaLanguage {
return LunaLanguage.VIETNAMESE;
return null;
}
}
extension LunaLanguageExtension on LunaLanguage {
bool get enabled {
switch (this) {
case LunaLanguage.ENGLISH:

View File

@@ -5,6 +5,7 @@ import 'package:lunasea/database/tables/lunasea.dart';
import 'package:lunasea/deprecated/state/state.dart';
import 'package:lunasea/system/logger.dart';
import 'package:lunasea/types/exception.dart';
import 'package:lunasea/vendor.dart';
import 'package:lunasea/widgets/ui.dart';
class LunaProfileTools {

View File

@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
export 'package:easy_localization/easy_localization.dart';
export 'ui/appbar.dart';
export 'ui/assets.dart';
export 'ui/banner.dart';

View File

@@ -50,13 +50,23 @@
"lunasea.MinutesAgo": "{} Minutes Ago",
"lunasea.Module": "Module",
"lunasea.ModuleIsNotEnabled": "{} Is Not Enabled",
"lunasea.Months": "{} Months",
"lunasea.MonthsAgo": "{} Months Ago",
"lunasea.New": "New",
"lunasea.NotSet": "Not Set",
"lunasea.NoModulesEnabled": "No Modules Enabled",
"lunasea.OneDay": "1 Day",
"lunasea.OneDayAgo": "1 Day Ago",
"lunasea.OneHour": "1 Hour",
"lunasea.OneHourAgo": "1 Hour Ago",
"lunasea.OneMinute": "1 Minute",
"lunasea.OneMinuteAgo": "1 Minute Ago",
"lunasea.OneMonth": "1 Month",
"lunasea.OneMonthAgo": "1 Month Ago",
"lunasea.OneSecond": "1 Second",
"lunasea.OneSecondAgo": "1 Second Ago",
"lunasea.OneYear": "1 Year",
"lunasea.OneYearAgo": "1 Year Ago",
"lunasea.Options": "Options",
"lunasea.Page": "Page",
"lunasea.PlatformSpecific": "Platform-Specific",
@@ -76,6 +86,7 @@
"lunasea.Settings": "Settings",
"lunasea.Stable": "Stable",
"lunasea.StartingView": "Starting View",
"lunasea.Today": "Today",
"lunasea.TransactionFailure": "Transaction Failure",
"lunasea.TryAgain": "Try Again",
"lunasea.Tweaks": "Tweaks",
@@ -87,5 +98,7 @@
"lunasea.Update": "Update",
"lunasea.View": "View",
"lunasea.Warning": "Warning",
"lunasea.Website": "Website"
"lunasea.Website": "Website",
"lunasea.Years": "{} Years",
"lunasea.YearsAgo": "{} Years Ago"
}