diff --git a/android/fastlane/metadata/android/en-US/changelogs/156.txt b/android/fastlane/metadata/android/en-US/changelogs/156.txt new file mode 100644 index 0000000000..f75a915f7e --- /dev/null +++ b/android/fastlane/metadata/android/en-US/changelogs/156.txt @@ -0,0 +1 @@ +- “Added full timestamp display for ‘Last Updated’ and ‘Date Created’ in Drive Explorer and details panel. diff --git a/lib/components/details_panel.dart b/lib/components/details_panel.dart index c0775bba7c..41feae5c6c 100644 --- a/lib/components/details_panel.dart +++ b/lib/components/details_panel.dart @@ -15,7 +15,6 @@ import 'package:ardrive/core/arfs/entities/arfs_entities.dart'; import 'package:ardrive/core/crypto/crypto.dart'; import 'package:ardrive/download/multiple_file_download_modal.dart'; import 'package:ardrive/drive_explorer/thumbnail_creation/page/thumbnail_creation_modal.dart'; -import 'package:ardrive/l11n/l11n.dart'; import 'package:ardrive/misc/resources.dart'; import 'package:ardrive/models/models.dart'; import 'package:ardrive/pages/drive_detail/components/drive_explorer_item_tile.dart'; @@ -26,6 +25,7 @@ import 'package:ardrive/services/services.dart'; import 'package:ardrive/theme/theme.dart'; import 'package:ardrive/utils/app_localizations_wrapper.dart'; import 'package:ardrive/utils/filesize.dart'; +import 'package:ardrive/utils/format_date.dart'; import 'package:ardrive/utils/num_to_string_parsers.dart'; import 'package:ardrive/utils/open_url.dart'; import 'package:ardrive/utils/show_general_dialog.dart'; @@ -602,7 +602,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(widget.item.lastUpdated), + formatDateToUtcString(widget.item.lastUpdated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).lastUpdated, @@ -610,7 +610,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(widget.item.dateCreated), + formatDateToUtcString(widget.item.dateCreated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).dateCreated, @@ -672,7 +672,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(widget.item.lastUpdated), + formatDateToUtcString(widget.item.lastUpdated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).lastUpdated, @@ -680,7 +680,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(widget.item.dateCreated), + formatDateToUtcString(widget.item.dateCreated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).dateCreated, @@ -724,7 +724,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(item.lastUpdated), + formatDateToUtcString(item.lastUpdated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).lastUpdated, @@ -732,7 +732,7 @@ class _DetailsPanelState extends State { sizedBoxHeight16px, DetailsPanelItem( leading: Text( - yMMdDateFormatter.format(item.dateCreated), + formatDateToUtcString(item.dateCreated), style: typography.paragraphNormal(), ), itemTitle: appLocalizationsOf(context).dateCreated, @@ -901,7 +901,7 @@ class _DetailsPanelState extends State { default: title = appLocalizationsOf(context).folderWasModified; } - subtitle = yMMdDateFormatter.format(revision.dateCreated); + subtitle = formatDateToUtcString(revision.dateCreated); return DetailsPanelItem( itemSubtitle: subtitle, @@ -944,7 +944,7 @@ class _DetailsPanelState extends State { title = appLocalizationsOf(context).driveWasModified; } - subtitle = yMMdDateFormatter.format(revision.dateCreated); + subtitle = formatDateToUtcString(revision.dateCreated); return DetailsPanelItem( itemSubtitle: subtitle, @@ -1023,7 +1023,7 @@ class _DetailsPanelState extends State { default: title = appLocalizationsOf(context).fileWasModified; } - subtitle = yMMdDateFormatter.format(file.unixTime); + subtitle = formatDateToUtcString(file.unixTime); return DetailsPanelItem( leading: leading ?? const SizedBox(), diff --git a/lib/pages/drive_detail/components/drive_detail_data_list.dart b/lib/pages/drive_detail/components/drive_detail_data_list.dart index 8f2a4f528c..c566476806 100644 --- a/lib/pages/drive_detail/components/drive_detail_data_list.dart +++ b/lib/pages/drive_detail/components/drive_detail_data_list.dart @@ -200,8 +200,8 @@ Widget _buildDataListContent( name: row.name, typography: typography, size: row.size == null ? '-' : filesize(row.size), - lastUpdated: yMMdDateFormatter.format(row.lastUpdated), - dateCreated: yMMdDateFormatter.format(row.dateCreated), + lastUpdated: row.lastUpdated, + dateCreated: row.dateCreated, dataTableItem: row, license: row.licenseType == null ? '' diff --git a/lib/pages/drive_detail/components/drive_detail_data_table_source.dart b/lib/pages/drive_detail/components/drive_detail_data_table_source.dart deleted file mode 100644 index f4c4474c30..0000000000 --- a/lib/pages/drive_detail/components/drive_detail_data_table_source.dart +++ /dev/null @@ -1,272 +0,0 @@ -part of '../drive_detail_page.dart'; - -class DriveDetailDataTableSource extends DataTableSource { - final List folders; - final List files; - final BuildContext context; - final bool checkBoxEnabled; - DriveDetailDataTableSource({ - required this.folders, - required this.files, - required this.context, - required this.checkBoxEnabled, - }); - - @override - DataRow? getRow(int index) { - assert(index >= 0); - - if (index >= rowCount) { - return null; - } - - if (index < folders.length) { - final folder = folders[index]; - return _buildFolderRow( - context: context, - folder: folder.folder, - onPressed: folder.onPressed, - index: index, - selected: folder.selected, - checkBoxEnabled: checkBoxEnabled, - ); - } else { - final fileIndex = index - folders.length; - final file = files[fileIndex]; - return _buildFileRow( - context: context, - file: file.file, - onPressed: file.onPressed, - index: index, - checkBoxEnabled: checkBoxEnabled, - selected: file.selected, - ); - } - } - - @override - bool get isRowCountApproximate => false; - - @override - int get rowCount => folders.length + files.length; - - @override - int get selectedRowCount => 0; -} - -class DriveTableFile { - final FileWithLatestRevisionTransactions file; - final bool selected; - final Function onPressed; - - DriveTableFile({ - required this.file, - required this.selected, - required this.onPressed, - }); -} - -class DriveTableFolder { - final FolderEntry folder; - final bool selected; - final Function onPressed; - - DriveTableFolder({ - required this.folder, - required this.selected, - required this.onPressed, - }); -} - -String trimName({required String name, required BuildContext context}) { - const endBuffer = 8; - final width = MediaQuery.of(context).size.width; - // No better way to do this. Lerping is too gradual and causes overlap. - var stringLength = width > 1600 - ? 75 - : width > 1400 - ? 50 - : width > 1200 - ? 35 - : 20; - - // If info sidebar is closed increase the width - final driveState = context.read().state; - if (driveState is DriveDetailLoadSuccess && - !driveState.showSelectedItemDetails) { - stringLength += 20; - } - return name.length > stringLength - ? '${name.substring(0, stringLength - endBuffer)} ... ${name.substring(name.length - endBuffer)}' - : name; -} - -DataRow _buildFolderRow({ - required BuildContext context, - required FolderEntry folder, - bool selected = false, - required Function onPressed, - required int index, - required bool checkBoxEnabled, -}) { - return DataRow.byIndex( - onSelectChanged: (_) => onPressed(), - selected: selected, - index: index, - cells: [ - if (checkBoxEnabled) - DataCell( - AbsorbPointer(child: Checkbox(value: selected, onChanged: (_) {})), - ) - else - const DataCell(SizedBox(width: 32)), - DataCell( - Row( - children: [ - const Padding( - padding: EdgeInsetsDirectional.only(end: 8.0), - child: Icon(Icons.folder), - ), - Text( - trimName(name: folder.name, context: context), - ), - ], - ), - ), - const DataCell(Text('-')), - folder.isGhost - ? DataCell( - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: LightColors.kOnLightSurfaceMediumEmphasis, - textStyle: const TextStyle( - color: LightColors.kOnDarkSurfaceHighEmphasis), - ), - onPressed: () => - showCongestionDependentModalDialog(context, () => null), - child: Text(appLocalizationsOf(context).fix), - ), - ) - : const DataCell(Text('-')), - ], - ); -} - -DataRow _buildFileRow({ - required BuildContext context, - required FileWithLatestRevisionTransactions file, - bool selected = false, - required Function onPressed, - required int index, - required bool checkBoxEnabled, -}) { - return DataRow.byIndex( - index: index, - onSelectChanged: (_) => onPressed(), - selected: selected, - cells: [ - if (checkBoxEnabled) - DataCell( - AbsorbPointer(child: Checkbox(value: selected, onChanged: (_) {})), - ) - else - const DataCell(SizedBox(width: 32)), - DataCell( - Row( - children: [ - Padding( - padding: const EdgeInsetsDirectional.only(end: 8.0), - child: _buildFileIcon( - fileStatusFromTransactions(file.metadataTx, file.dataTx), - file.dataContentType, - appLocalizationsOf(context), - ), - ), - Text( - trimName(name: file.name, context: context), - ), - ], - ), - ), - DataCell(Text(filesize(file.size))), - DataCell( - Text( - // Show a relative timestamp if the file was updated at most 3 days ago. - file.lastUpdated.difference(DateTime.now()).inDays > 3 - ? format(file.lastUpdated) - : yMMdDateFormatter.format(file.lastUpdated), - ), - ), - ], - ); -} - -Widget _buildFileIcon( - String status, - String? dataContentType, - AppLocalizations localizations, -) { - String tooltipMessage; - Color indicatorColor; - Widget icon; - - switch (status) { - case TransactionStatus.pending: - tooltipMessage = localizations.pending; - indicatorColor = Colors.orange; - break; - case TransactionStatus.confirmed: - tooltipMessage = localizations.confirmed; - indicatorColor = Colors.green; - break; - case TransactionStatus.failed: - tooltipMessage = localizations.failed; - indicatorColor = Colors.red; - break; - default: - throw ArgumentError(); - } - - if (dataContentType == entities.ContentType.manifest) { - icon = const Icon(Icons.account_tree_outlined); - } else { - final fileType = dataContentType?.split('/').first; - switch (fileType) { - case 'image': - icon = const Icon(Icons.image); - break; - case 'video': - icon = const Icon(Icons.ondemand_video); - break; - case 'audio': - icon = const Icon(Icons.music_note); - break; - default: - icon = const Icon(Icons.insert_drive_file); - } - } - - return ArDriveTooltip( - message: tooltipMessage, - child: Stack( - children: [ - icon, - Positioned( - right: 0, - bottom: 0, - child: Container( - padding: const EdgeInsets.all(1), - decoration: BoxDecoration( - color: indicatorColor, - borderRadius: BorderRadius.circular(6), - ), - constraints: const BoxConstraints( - minWidth: 8, - minHeight: 8, - ), - ), - ), - ], - ), - ); -} diff --git a/lib/pages/drive_detail/components/drive_explorer_item_tile.dart b/lib/pages/drive_detail/components/drive_explorer_item_tile.dart index b6f5003271..dc8010551a 100644 --- a/lib/pages/drive_detail/components/drive_explorer_item_tile.dart +++ b/lib/pages/drive_detail/components/drive_explorer_item_tile.dart @@ -11,12 +11,14 @@ import 'package:ardrive/components/pin_indicator.dart'; import 'package:ardrive/download/multiple_file_download_modal.dart'; import 'package:ardrive/drive_explorer/thumbnail/repository/thumbnail_repository.dart'; import 'package:ardrive/drive_explorer/thumbnail/thumbnail_bloc.dart'; +import 'package:ardrive/l11n/l11n.dart'; import 'package:ardrive/models/models.dart'; import 'package:ardrive/pages/congestion_warning_wrapper.dart'; import 'package:ardrive/pages/drive_detail/components/dropdown_item.dart'; import 'package:ardrive/pages/drive_detail/components/hover_widget.dart'; import 'package:ardrive/pages/drive_detail/models/data_table_item.dart'; import 'package:ardrive/utils/app_localizations_wrapper.dart'; +import 'package:ardrive/utils/format_date.dart'; import 'package:ardrive/utils/logger.dart'; import 'package:ardrive/utils/size_constants.dart'; import 'package:ardrive_ui/ardrive_ui.dart'; @@ -28,8 +30,8 @@ class DriveExplorerItemTile extends TableRowWidget { DriveExplorerItemTile({ required String name, required String size, - required String lastUpdated, - required String dateCreated, + required DateTime lastUpdated, + required DateTime dateCreated, required String license, required Function() onPressed, required bool isHidden, @@ -68,12 +70,18 @@ class DriveExplorerItemTile extends TableRowWidget { Text(size, style: _driveExplorerItemTileTextStyle( isHidden, typography, colorTokens)), - Text(lastUpdated, - style: _driveExplorerItemTileTextStyle( - isHidden, typography, colorTokens)), - Text(dateCreated, - style: _driveExplorerItemTileTextStyle( - isHidden, typography, colorTokens)), + ArDriveTooltip( + message: formatDateToUtcString(lastUpdated), + child: Text(yMMdDateFormatter.format(lastUpdated), + style: _driveExplorerItemTileTextStyle( + isHidden, typography, colorTokens)), + ), + ArDriveTooltip( + message: formatDateToUtcString(dateCreated), + child: Text(yMMdDateFormatter.format(dateCreated), + style: _driveExplorerItemTileTextStyle( + isHidden, typography, colorTokens)), + ), Text(license, style: ArDriveTypography.body.captionRegular()), ], ); diff --git a/lib/pages/drive_detail/drive_detail_page.dart b/lib/pages/drive_detail/drive_detail_page.dart index 836100cc5f..1441c48b36 100644 --- a/lib/pages/drive_detail/drive_detail_page.dart +++ b/lib/pages/drive_detail/drive_detail_page.dart @@ -27,11 +27,9 @@ import 'package:ardrive/core/activity_tracker.dart'; import 'package:ardrive/dev_tools/app_dev_tools.dart'; import 'package:ardrive/dev_tools/shortcut_handler.dart'; import 'package:ardrive/download/multiple_file_download_modal.dart'; -import 'package:ardrive/entities/entities.dart' as entities; import 'package:ardrive/l11n/l11n.dart'; import 'package:ardrive/misc/resources.dart'; import 'package:ardrive/models/models.dart'; -import 'package:ardrive/pages/congestion_warning_wrapper.dart'; import 'package:ardrive/pages/drive_detail/components/drive_explorer_item_tile.dart'; import 'package:ardrive/pages/drive_detail/components/drive_file_drop_zone.dart'; import 'package:ardrive/pages/drive_detail/components/dropdown_item.dart'; @@ -45,7 +43,6 @@ import 'package:ardrive/services/services.dart'; import 'package:ardrive/shared/components/plausible_page_view_wrapper.dart'; import 'package:ardrive/sharing/sharing_file_listener.dart'; import 'package:ardrive/sync/domain/cubit/sync_cubit.dart'; -import 'package:ardrive/theme/theme.dart'; import 'package:ardrive/utils/app_localizations_wrapper.dart'; import 'package:ardrive/utils/compare_alphabetically_and_natural.dart'; import 'package:ardrive/utils/filesize.dart'; @@ -62,18 +59,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_svg/svg.dart'; import 'package:just_audio/just_audio.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:synchronized/synchronized.dart'; -import 'package:timeago/timeago.dart'; import 'package:video_player/video_player.dart'; import 'package:visibility_detector/visibility_detector.dart'; part 'components/drive_detail_breadcrumb_row.dart'; part 'components/drive_detail_data_list.dart'; -part 'components/drive_detail_data_table_source.dart'; part 'components/drive_detail_folder_empty_card.dart'; part 'components/fs_entry_preview_widget.dart'; diff --git a/lib/utils/format_date.dart b/lib/utils/format_date.dart new file mode 100644 index 0000000000..e7f36c7245 --- /dev/null +++ b/lib/utils/format_date.dart @@ -0,0 +1,8 @@ +import 'package:intl/intl.dart'; + +String formatDateToUtcString(DateTime date) { + String formattedDate = + '${DateFormat('yyyy-MM-dd HH:mm:ss').format(date.toUtc())} GMT+0'; + + return formattedDate; +} diff --git a/pubspec.yaml b/pubspec.yaml index 0ca1590278..bcb3fd057e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Secure, permanent storage publish_to: 'none' -version: 2.54.5 +version: 2.55.0 environment: sdk: '>=3.2.0 <4.0.0'