consolidated downloads dir, nextcloud origin, upload route and chat timestamps; added webdav path tests
This commit is contained in:
@@ -2,10 +2,10 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../../api/marianumcloud/webdav/queries/list_files/cacheable_file.dart';
|
||||
import '../../../api/marianumcloud/webdav/queries/list_files/list_files_response.dart';
|
||||
import '../../../routing/app_routes.dart';
|
||||
import '../../../state/app/infrastructure/loadable_state/loadable_state.dart';
|
||||
import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart';
|
||||
import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart';
|
||||
@@ -15,7 +15,6 @@ import '../../../utils/cache_invalidation_bus.dart';
|
||||
import '../../../widget/placeholder_view.dart';
|
||||
import 'data/file_sort.dart';
|
||||
import 'data/webdav_path.dart';
|
||||
import 'files_upload_dialog.dart';
|
||||
import 'search/files_search_delegate.dart';
|
||||
import 'widgets/add_file_menu.dart';
|
||||
import 'widgets/clipboard_banner.dart';
|
||||
@@ -82,14 +81,11 @@ class _FilesViewState extends State<_FilesView> {
|
||||
if (paths == null) return;
|
||||
final bloc = context.read<FilesBloc>();
|
||||
unawaited(
|
||||
pushScreen(
|
||||
AppRoutes.openFilesUpload(
|
||||
context,
|
||||
withNavBar: false,
|
||||
screen: FilesUploadDialog(
|
||||
filePaths: paths,
|
||||
remotePath: widget.path.join('/'),
|
||||
onUploadFinished: (_) => bloc.refresh(),
|
||||
),
|
||||
filePaths: paths,
|
||||
remotePath: widget.path.join('/'),
|
||||
onUploadFinished: (_) => bloc.refresh(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class FileLeading extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl:
|
||||
'https://${EndpointData().nextcloud().full()}'
|
||||
'${EndpointData().nextcloud().origin()}'
|
||||
'/index.php/core/preview'
|
||||
'?fileId=$fileId&x=128&y=128&a=0',
|
||||
httpHeaders: SessionManager().requireNextcloud().authHeaders,
|
||||
|
||||
@@ -94,7 +94,7 @@ class _DiagnosticsPageState extends State<DiagnosticsPage> {
|
||||
rows: await rows({
|
||||
'Marianum Connect': () async => MarianumConnectEndpoint.current(),
|
||||
'Nextcloud': () async =>
|
||||
'https://${EndpointData().nextcloud().full()}',
|
||||
EndpointData().nextcloud().origin(),
|
||||
'Notfall-Nachricht': () async =>
|
||||
settings.devToolsSettings.resolveEmergencyNoticeUrl(),
|
||||
}),
|
||||
|
||||
@@ -121,8 +121,7 @@ class DevToolsSection extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () =>
|
||||
MarianumConnectEndpointPicker.show(context, settings),
|
||||
onTap: () => MarianumConnectEndpointPicker.show(context, settings),
|
||||
),
|
||||
BlocBuilder<SettingsCubit, model.Settings>(
|
||||
bloc: settings,
|
||||
@@ -137,8 +136,7 @@ class DevToolsSection extends StatelessWidget {
|
||||
title: const Text('Notfall-Nachrichtenquelle'),
|
||||
subtitle: Text(override.isEmpty ? 'Standardquelle' : override),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () =>
|
||||
_EmergencyNoticeUrlEditor.show(context, settings),
|
||||
onTap: () => _EmergencyNoticeUrlEditor.show(context, settings),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -146,9 +144,8 @@ class DevToolsSection extends StatelessWidget {
|
||||
_StorageTile(
|
||||
icon: Icons.settings_applications_outlined,
|
||||
title: 'Einstellungen',
|
||||
describe: () async => filesize(
|
||||
utf8.encode(jsonEncode(settings.val().toJson())).length,
|
||||
),
|
||||
describe: () async =>
|
||||
filesize(utf8.encode(jsonEncode(settings.val().toJson())).length),
|
||||
onOpen: (_) async => AppRoutes.openJsonViewer(
|
||||
context,
|
||||
settings.val().toJson(),
|
||||
@@ -235,15 +232,16 @@ class DevToolsSection extends StatelessWidget {
|
||||
_StorageTile(
|
||||
icon: Icons.download_outlined,
|
||||
title: 'Downloads',
|
||||
describe: () async =>
|
||||
filesize(await directorySize(await _downloadsDir())),
|
||||
describe: () async => filesize(
|
||||
await directorySize(await DownloadManager.downloadsDirectory()),
|
||||
),
|
||||
clearTitle: 'Downloads löschen',
|
||||
clearContent:
|
||||
'Laufende Downloads werden abgebrochen und heruntergeladene '
|
||||
'Dateien gelöscht.',
|
||||
onClear: () async {
|
||||
DownloadManager.instance.clearAll();
|
||||
final dir = await _downloadsDir();
|
||||
final dir = await DownloadManager.downloadsDirectory();
|
||||
if (!dir.existsSync()) return;
|
||||
// Cancelled tasks can still be flushing into the folder, so deleting
|
||||
// it as a whole races them; whatever survives shows up in the size.
|
||||
@@ -258,9 +256,6 @@ class DevToolsSection extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
static Future<Directory> _downloadsDir() async =>
|
||||
Directory('${(await getTemporaryDirectory()).path}/downloads');
|
||||
}
|
||||
|
||||
/// Storage row: tap opens a detail view ([onOpen]), the trailing button clears
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../../api/errors/error_mapper.dart';
|
||||
import '../../../api/marianumcloud/talk/room/get_room_response.dart';
|
||||
@@ -20,7 +19,6 @@ import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import '../../../widget/app_progress_indicator.dart';
|
||||
import '../../../widget/info_dialog.dart';
|
||||
import '../../../widget/placeholder_view.dart';
|
||||
import '../files/files_upload_dialog.dart';
|
||||
import '../talk/search_chat.dart';
|
||||
import '../talk/widgets/chat_tile.dart';
|
||||
|
||||
@@ -144,16 +142,13 @@ Future<void> _externalShareFlow(
|
||||
try {
|
||||
await ensureTalkShareFolder();
|
||||
if (!context.mounted) return;
|
||||
await pushScreen(
|
||||
await AppRoutes.openFilesUpload(
|
||||
context,
|
||||
withNavBar: false,
|
||||
screen: FilesUploadDialog(
|
||||
filePaths: share.filePaths,
|
||||
remotePath: talkShareFolder,
|
||||
uniqueNames: true,
|
||||
onUploadFinished: (uploaded) =>
|
||||
_afterExternalFilesUploaded(context, room, uploaded, share),
|
||||
),
|
||||
filePaths: share.filePaths,
|
||||
remotePath: talkShareFolder,
|
||||
uniqueNames: true,
|
||||
onUploadFinished: (uploaded) =>
|
||||
_afterExternalFilesUploaded(context, room, uploaded, share),
|
||||
);
|
||||
} finally {
|
||||
ShareIntentListener.instance.endFlow();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../../api/errors/error_mapper.dart';
|
||||
import '../../../routing/app_routes.dart';
|
||||
@@ -17,7 +16,6 @@ import '../../../widget/centered_leading.dart';
|
||||
import '../../../widget/info_dialog.dart';
|
||||
import '../../../widget/placeholder_view.dart';
|
||||
import '../files/data/file_sort.dart';
|
||||
import '../files/files_upload_dialog.dart';
|
||||
import '../files/widgets/add_file_menu.dart';
|
||||
import '../files/widgets/file_leading.dart';
|
||||
import '../files/widgets/files_sort_actions.dart';
|
||||
@@ -173,15 +171,12 @@ Future<void> _externalUploadFlow(
|
||||
) async {
|
||||
ShareIntentListener.instance.beginFlow();
|
||||
try {
|
||||
await pushScreen(
|
||||
await AppRoutes.openFilesUpload(
|
||||
context,
|
||||
withNavBar: false,
|
||||
screen: FilesUploadDialog(
|
||||
filePaths: share.filePaths,
|
||||
remotePath: targetPath.join('/'),
|
||||
onUploadFinished: (_) =>
|
||||
_afterExternalUploaded(context, targetPath, share),
|
||||
),
|
||||
filePaths: share.filePaths,
|
||||
remotePath: targetPath.join('/'),
|
||||
onUploadFinished: (_) =>
|
||||
_afterExternalUploaded(context, targetPath, share),
|
||||
);
|
||||
} finally {
|
||||
ShareIntentListener.instance.endFlow();
|
||||
|
||||
@@ -304,9 +304,7 @@ class _ChatViewState extends State<ChatView> with RouteAware {
|
||||
for (final element in response.sortByTimestamp()) {
|
||||
if (ChatSearchController.isHiddenSystemMessage(element)) continue;
|
||||
|
||||
final elementDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
element.timestamp * 1000,
|
||||
);
|
||||
final elementDate = element.sentAt;
|
||||
|
||||
if (!elementDate.isSameDay(lastDate)) {
|
||||
lastDate = elementDate;
|
||||
|
||||
@@ -106,7 +106,7 @@ class ChatMessage {
|
||||
errorListener: (value) {},
|
||||
httpHeaders: SessionManager().requireNextcloud().authHeaders,
|
||||
imageUrl:
|
||||
'https://${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file.id}&x=130&y=-1&a=1',
|
||||
'${EndpointData().nextcloud().origin()}/index.php/core/preview?fileId=${file.id}&x=130&y=-1&a=1',
|
||||
),
|
||||
if (originalMessage != '{file}') ...[
|
||||
SizedBox(height: 5),
|
||||
|
||||
@@ -511,7 +511,7 @@ class _SharedItemTileState extends State<_SharedItemTile>
|
||||
}
|
||||
|
||||
String get _previewUrl =>
|
||||
'https://${EndpointData().nextcloud().full()}'
|
||||
'${EndpointData().nextcloud().origin()}'
|
||||
'/index.php/core/preview?fileId=${_file.id}&x=300&y=300&a=1';
|
||||
|
||||
bool get _isVideo => _isVideoFile(_file.name);
|
||||
@@ -586,7 +586,7 @@ class _SharedItemTileState extends State<_SharedItemTile>
|
||||
title: Text(_file.name, maxLines: 2, overflow: TextOverflow.ellipsis),
|
||||
subtitle: Text(
|
||||
'${widget.item.actorDisplayName} · '
|
||||
'${DateTime.fromMillisecondsSinceEpoch(widget.item.timestamp * 1000).formatDateShort()}',
|
||||
'${widget.item.sentAt.formatDateShort()}',
|
||||
),
|
||||
trailing: _isDownloading
|
||||
? SizedBox(
|
||||
|
||||
@@ -257,9 +257,7 @@ class _ChatBubbleState extends State<ChatBubble>
|
||||
: actorText;
|
||||
|
||||
final timeText = Text(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
widget.bubbleData.timestamp * 1000,
|
||||
).formatHm(),
|
||||
widget.bubbleData.sentAt.formatHm(),
|
||||
textAlign: TextAlign.end,
|
||||
style: const TextStyle(color: _kTimeIconColor, fontSize: _kTimeIconSize),
|
||||
);
|
||||
|
||||
@@ -67,9 +67,7 @@ void showChatMessageOptionsDialog(
|
||||
final hasReactions = bubbleData.reactions?.isNotEmpty ?? false;
|
||||
final canDelete =
|
||||
isSender &&
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
bubbleData.timestamp * 1000,
|
||||
).add(const Duration(hours: 6)).isAfter(DateTime.now());
|
||||
bubbleData.sentAt.add(const Duration(hours: 6)).isAfter(DateTime.now());
|
||||
final attachedFile = _attachedFile(bubbleData);
|
||||
|
||||
showDetailsBottomSheet(
|
||||
|
||||
@@ -2,12 +2,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../../../api/marianumcloud/talk/room/get_room_response.dart';
|
||||
import '../../../../api/marianumcloud/talk/send_message/send_message.dart';
|
||||
import '../../../../api/marianumcloud/talk/send_message/send_message_params.dart';
|
||||
import '../../../../api/marianumcloud/talk/share_files_to_chat.dart';
|
||||
import '../../../../routing/app_routes.dart';
|
||||
import '../../../../state/app/modules/chat/bloc/chat_bloc.dart';
|
||||
import '../../../../state/app/modules/chat/bloc/chat_state.dart';
|
||||
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
@@ -18,7 +18,6 @@ import '../../../../widget/downloads/download_tray.dart';
|
||||
import '../../../../widget/emoji_picker_dialog.dart';
|
||||
import '../../../../widget/file_pick.dart';
|
||||
import '../../../../widget/focus_behaviour.dart';
|
||||
import '../../files/files_upload_dialog.dart';
|
||||
import 'answer_reference.dart';
|
||||
import 'poll_create_sheet.dart';
|
||||
|
||||
@@ -71,15 +70,12 @@ class _ChatTextfieldState extends State<ChatTextfield> {
|
||||
|
||||
if (!mounted) return;
|
||||
unawaited(
|
||||
pushScreen(
|
||||
AppRoutes.openFilesUpload(
|
||||
context,
|
||||
withNavBar: false,
|
||||
screen: FilesUploadDialog(
|
||||
filePaths: paths,
|
||||
remotePath: talkShareFolder,
|
||||
onUploadFinished: share,
|
||||
uniqueNames: true,
|
||||
),
|
||||
filePaths: paths,
|
||||
remotePath: talkShareFolder,
|
||||
onUploadFinished: share,
|
||||
uniqueNames: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ class _ChatTileState extends State<ChatTile> {
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
'${DateTime.fromMillisecondsSinceEpoch(widget.data.lastMessage.timestamp * 1000).formatRelative()}: '
|
||||
'${widget.data.lastMessage.sentAt.formatRelative()}: '
|
||||
'${_lastMessagePreview()}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user