multiple runtime bugfixes for 1.5.5+65
This commit is contained in:
@@ -4,10 +4,10 @@ import '../../../../api/errors/error_mapper.dart';
|
||||
import '../../../../api/marianumcloud/autocomplete/autocomplete_api.dart';
|
||||
import '../../../../api/marianumcloud/autocomplete/autocomplete_response.dart';
|
||||
import '../../../../api/marianumcloud/files_sharing/queries/share/share.dart';
|
||||
import '../../../../model/endpoint_data.dart';
|
||||
import '../../../../utils/debouncer.dart';
|
||||
import '../../../../utils/haptics.dart';
|
||||
import '../../../../widget/app_progress_indicator.dart';
|
||||
import '../../../../widget/user_avatar.dart';
|
||||
|
||||
/// Result of [ShareePickerPage]: a recipient to create a share for.
|
||||
class ShareeRef {
|
||||
@@ -209,16 +209,11 @@ class _ShareePickerPageState extends State<ShareePickerPage> {
|
||||
|
||||
Widget _resultTile(AutocompleteResponseObject object) {
|
||||
final isGroup = shareTypeFromSource(object.source) == kShareTypeGroup;
|
||||
// Nextcloud groups are not Talk rooms, so UserAvatar's group URL does not
|
||||
// apply to them — they keep a plain icon.
|
||||
final leading = isGroup
|
||||
? const CircleAvatar(child: Icon(Icons.groups_outlined))
|
||||
: CircleAvatar(
|
||||
foregroundImage: Image.network(
|
||||
'https://${EndpointData().nextcloud().full()}/avatar/${object.id}/128',
|
||||
).image,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
child: const Icon(Icons.person),
|
||||
);
|
||||
: UserAvatar(id: object.id, semanticLabel: object.label);
|
||||
return ListTile(
|
||||
leading: leading,
|
||||
title: Text(object.label),
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:nextcloud/nextcloud.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../../api/errors/error_mapper.dart';
|
||||
@@ -10,7 +9,6 @@ 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 '../../../api/marianumcloud/webdav/webdav_api.dart';
|
||||
import '../../../routing/app_routes.dart';
|
||||
import '../../../share_intent/pending_share.dart';
|
||||
import '../../../share_intent/remote_file_ref.dart';
|
||||
@@ -137,12 +135,7 @@ Future<void> _externalShareFlow(
|
||||
PendingShare share,
|
||||
) async {
|
||||
if (share.hasFiles) {
|
||||
try {
|
||||
final webdav = await WebdavApi.webdav;
|
||||
await webdav.mkcol(PathUri.parse('/$talkShareFolder'));
|
||||
} catch (_) {
|
||||
// mkcol throws when the folder already exists; ignore.
|
||||
}
|
||||
await ensureTalkShareFolder();
|
||||
if (!context.mounted) return;
|
||||
await pushScreen(
|
||||
context,
|
||||
|
||||
@@ -39,6 +39,7 @@ class _ChatInfoState extends State<ChatInfo> {
|
||||
GetParticipantsCache(
|
||||
chatToken: widget.room.token,
|
||||
onUpdate: (GetParticipantsResponse data) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
participants = data;
|
||||
});
|
||||
|
||||
@@ -2,14 +2,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:nextcloud/nextcloud.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 '../../../../api/marianumcloud/webdav/webdav_api.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';
|
||||
@@ -68,11 +66,7 @@ class _ChatTextfieldState extends State<ChatTextfield> {
|
||||
Future<void> mediaUpload(List<String>? paths) async {
|
||||
if (paths == null) return;
|
||||
|
||||
unawaited(
|
||||
WebdavApi.webdav.then(
|
||||
(webdav) => webdav.mkcol(PathUri.parse('/$talkShareFolder')),
|
||||
),
|
||||
);
|
||||
unawaited(ensureTalkShareFolder());
|
||||
|
||||
if (!mounted) return;
|
||||
unawaited(
|
||||
@@ -113,6 +107,7 @@ class _ChatTextfieldState extends State<ChatTextfield> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
settings = context.read<SettingsCubit>();
|
||||
_loadDraft();
|
||||
final draftReply = settings
|
||||
.val()
|
||||
.talkSettings
|
||||
@@ -122,6 +117,24 @@ class _ChatTextfieldState extends State<ChatTextfield> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant ChatTextfield oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
// The state survives a room switch in the split view, so the draft has to
|
||||
// follow the new token. Every edit persists through _setDraft, so the
|
||||
// outgoing room's draft is already stored at this point.
|
||||
if (oldWidget.sendToToken != widget.sendToToken) _loadDraft();
|
||||
}
|
||||
|
||||
/// Seeds the field from the stored draft. Only ever called on mount and on a
|
||||
/// room switch: `TextEditingController.text` resets selection and composing,
|
||||
/// so doing this per build would drop the cursor position, any active text
|
||||
/// selection and a running IME composition on every chat update.
|
||||
void _loadDraft() {
|
||||
_textBoxController.text =
|
||||
settings.val().talkSettings.drafts[widget.sendToToken] ?? '';
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Defer to end-of-frame: resetting the shared notifier synchronously during
|
||||
@@ -263,8 +276,6 @@ class _ChatTextfieldState extends State<ChatTextfield> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_textBoxController.text =
|
||||
settings.val().talkSettings.drafts[widget.sendToToken] ?? '';
|
||||
final chatBloc = context.watch<ChatBloc>();
|
||||
final chatState = chatBloc.state.data;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import '../../../state/app/infrastructure/utility_widgets/loadable_hydrated_bloc
|
||||
import '../../../state/app/modules/ticker/bloc/ticker_bloc.dart';
|
||||
import '../../../state/app/modules/ticker/bloc/ticker_state.dart';
|
||||
import '../../../theming/app_theme.dart';
|
||||
import '../../../utils/url_opener.dart';
|
||||
import '../../../widget/details_bottom_sheet.dart';
|
||||
import '../../../widget/placeholder_view.dart';
|
||||
import '../../../widget/prosemirror/pm_json_view.dart';
|
||||
@@ -247,7 +248,7 @@ class _TickerScaffoldState extends State<TickerScaffold> {
|
||||
void _openRedirect(TickerNavPage page) {
|
||||
final url = page.externalUrl;
|
||||
if (url != null && url.isNotEmpty) {
|
||||
unawaited(AppRoutes.openExternalUrl(url));
|
||||
unawaited(UrlOpener.openUrl(url));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ class _TickerScaffoldState extends State<TickerScaffold> {
|
||||
_ensureBackEntry();
|
||||
return;
|
||||
}
|
||||
unawaited(AppRoutes.openExternalUrl(href));
|
||||
unawaited(UrlOpener.openUrl(href));
|
||||
}
|
||||
|
||||
String? _titleForSlug(String slug) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import '../../../../state/app/modules/ticker/bloc/ticker_page_bloc.dart';
|
||||
import '../../../../state/app/modules/ticker/bloc/ticker_page_state.dart';
|
||||
import '../../../../state/app/modules/ticker/repository/ticker_page_repository.dart';
|
||||
import '../../../../theming/app_theme.dart';
|
||||
import '../../../../utils/url_opener.dart';
|
||||
import '../../../../widget/app_progress_indicator.dart';
|
||||
import '../../../../widget/placeholder_view.dart';
|
||||
import '../../../../widget/prosemirror/pm_json_view.dart';
|
||||
@@ -87,7 +88,7 @@ class _TickerPageContentState extends State<_TickerPageContent> {
|
||||
_redirected = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
if (url != null && url.isNotEmpty) AppRoutes.openExternalUrl(url);
|
||||
if (url != null && url.isNotEmpty) UrlOpener.openUrl(url);
|
||||
widget.onRedirect?.call();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user