From 05bc9034d184024d0d0a4559f793929d9cabf298 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 23 May 2026 20:14:33 -0400 Subject: [PATCH] measure size of chat box to dynamically adjust padding Fixes #21 --- lib/widgets/composer/chat_box.dart | 216 ++++++++++++++--------------- lib/widgets/room_chat.dart | 47 ++++--- pubspec.lock | 8 ++ pubspec.yaml | 1 + 4 files changed, 143 insertions(+), 129 deletions(-) diff --git a/lib/widgets/composer/chat_box.dart b/lib/widgets/composer/chat_box.dart index 4cb3835..4920c8e 100644 --- a/lib/widgets/composer/chat_box.dart +++ b/lib/widgets/composer/chat_box.dart @@ -63,126 +63,118 @@ class ChatBox extends HookConsumerWidget { fontWeight: FontWeight.bold, ); - return Positioned( - bottom: 0, - left: 0, - right: 0, - child: Padding( - padding: EdgeInsetsGeometry.all(12), - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(12)), - child: Column( - children: [ - RelationPreview( - relatedEvent, - shouldMention: shouldMention.value, - toggleShouldMention: () => - shouldMention.value = !shouldMention.value, - relationType: relationType, - onDismiss: onDismiss, - ), - Container( - color: theme.colorScheme.surfaceContainerHighest, - padding: EdgeInsets.symmetric(horizontal: 8), - child: Row( - spacing: 8, - mainAxisAlignment: MainAxisAlignment.center, - children: - ref.watch( - PowerLevelController.provider( - PowerLevelConfig( - eventType: EventType.message, - roomId: roomId, - ), + return Padding( + padding: EdgeInsetsGeometry.all(12), + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(12)), + child: Column( + children: [ + RelationPreview( + relatedEvent, + shouldMention: shouldMention.value, + toggleShouldMention: () => + shouldMention.value = !shouldMention.value, + relationType: relationType, + onDismiss: onDismiss, + ), + Container( + color: theme.colorScheme.surfaceContainerHighest, + padding: EdgeInsets.symmetric(horizontal: 8), + child: Row( + spacing: 8, + mainAxisAlignment: MainAxisAlignment.center, + children: + ref.watch( + PowerLevelController.provider( + PowerLevelConfig( + eventType: EventType.message, + roomId: roomId, ), - ) - ? [ - EmojiPickerButton( - context: context, - onSelection: (_) => node?.requestFocus(), + ), + ) + ? [ + EmojiPickerButton( + context: context, + onSelection: (_) => node?.requestFocus(), + controller: controller.value, + ), + PopupMenuButton( + tooltip: "Add media", + itemBuilder: (context) => [ + PopupMenuItem( + child: ListTile( + title: Text("Camera"), + leading: Icon(Icons.add_a_photo), + ), + ), + PopupMenuItem( + child: ListTile( + title: Text("Gallery"), + leading: Icon(Icons.add_photo_alternate), + ), + ), + PopupMenuItem( + child: ListTile( + title: Text("Files"), + leading: Icon(Icons.attachment), + ), + ), + ], + icon: Icon(Icons.add), + ), + Expanded( + child: FlutterTagger( + triggerStrategy: TriggerStrategy.eager, + overlay: MentionOverlay( + roomId, + query: query.value, + triggerCharacter: triggerCharacter.value, + addTag: ({required id, required name}) { + controller.value.addTag(id: id, name: name); + node?.requestFocus(); + }, + ), controller: controller.value, - ), - PopupMenuButton( - tooltip: "Add media", - itemBuilder: (context) => [ - PopupMenuItem( - child: ListTile( - title: Text("Camera"), - leading: Icon(Icons.add_a_photo), - ), - ), - PopupMenuItem( - child: ListTile( - title: Text("Gallery"), - leading: Icon(Icons.add_photo_alternate), - ), - ), - PopupMenuItem( - child: ListTile( - title: Text("Files"), - leading: Icon(Icons.attachment), - ), - ), - ], - icon: Icon(Icons.add), - ), - Expanded( - child: FlutterTagger( - triggerStrategy: TriggerStrategy.eager, - overlay: MentionOverlay( - roomId, - query: query.value, - triggerCharacter: triggerCharacter.value, - addTag: ({required id, required name}) { - controller.value.addTag(id: id, name: name); - node?.requestFocus(); - }, + onSearch: (newQuery, newTriggerCharacter) { + triggerCharacter.value = newTriggerCharacter; + query.value = newQuery; + }, + triggerCharacterAndStyles: {"@": style, "#": style}, + builder: (context, key) => TextFormField( + maxLines: 12, + minLines: 1, + autofocus: true, + decoration: InputDecoration( + hintText: "Your message here...", + border: InputBorder.none, ), controller: controller.value, - onSearch: (newQuery, newTriggerCharacter) { - triggerCharacter.value = newTriggerCharacter; - query.value = newQuery; - }, - triggerCharacterAndStyles: { - "@": style, - "#": style, - }, - builder: (context, key) => TextFormField( - maxLines: 12, - minLines: 1, - autofocus: true, - decoration: InputDecoration( - hintText: "Your message here...", - border: InputBorder.none, - ), - controller: controller.value, - key: key, - onFieldSubmitted: (_) => send(), - // Don't defocus on submit - onEditingComplete: () {}, - textInputAction: TextInputAction.done, - focusNode: node, - ), + key: key, + onFieldSubmitted: (_) => send(), + // Don't defocus on submit + onEditingComplete: () {}, + textInputAction: TextInputAction.done, + focusNode: node, ), ), - IconButton( - onPressed: send, - icon: Icon(Icons.send), - tooltip: "Send message", + ), + IconButton( + onPressed: send, + icon: Icon(Icons.send), + tooltip: "Send message", + ), + ] + : [ + Padding( + padding: EdgeInsetsGeometry.all(8), + child: Text( + "You don't have permission to send messages in this room...", ), - ] - : [ - Padding( - padding: EdgeInsetsGeometry.all(8), - child: Text( - "You don't have permission to send messages in this room...", - ), - ), - ], - ), + ), + ], ), - ], - ), + ), + ], ), ), ); diff --git a/lib/widgets/room_chat.dart b/lib/widgets/room_chat.dart index 249f2d2..b9f8fc6 100644 --- a/lib/widgets/room_chat.dart +++ b/lib/widgets/room_chat.dart @@ -3,6 +3,7 @@ import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_hooks/flutter_hooks.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:measure_size/measure_size.dart"; import "package:nexus/controllers/account_data_controller.dart"; import "package:nexus/controllers/client_controller.dart"; import "package:nexus/controllers/client_state_controller.dart"; @@ -45,6 +46,8 @@ class RoomChat extends HookConsumerWidget { final relationType = useState(RelationType.reply); final flashingEvent = useState(null); + final composerSize = useState(64); + final memberListOpened = useState(showMembersByDefault); final userId = ref.watch(ClientStateController.provider)?.userId; @@ -346,7 +349,9 @@ class RoomChat extends HookConsumerWidget { controller: scrollController, slivers: [ SliverPadding( - padding: EdgeInsetsGeometry.only(bottom: 64), + padding: EdgeInsetsGeometry.only( + bottom: composerSize.value, + ), ), SuperSliverList.builder( @@ -416,22 +421,30 @@ class RoomChat extends HookConsumerWidget { }, ), ), - ChatBox( - roomId, - node: composerNode, - onSend: (text, {required shouldMention, required tags}) => - notifier - .send( - text, - tags: tags, - relationType: relationType.value, - shouldMention: shouldMention, - relation: relatedEvent.value, - ) - .onError(showError), - relationType: relationType.value, - relatedEvent: relatedEvent.value, - onDismiss: () => relatedEvent.value = null, + Positioned( + bottom: 0, + left: 0, + right: 0, + child: MeasureSize( + onChange: (size) => composerSize.value = size.height, + child: ChatBox( + roomId, + node: composerNode, + onSend: (text, {required shouldMention, required tags}) => + notifier + .send( + text, + tags: tags, + relationType: relationType.value, + shouldMention: shouldMention, + relation: relatedEvent.value, + ) + .onError(showError), + relationType: relationType.value, + relatedEvent: relatedEvent.value, + onDismiss: () => relatedEvent.value = null, + ), + ), ), ], ), diff --git a/pubspec.lock b/pubspec.lock index 6d3aa22..4d1d9a1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -760,6 +760,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.0" + measure_size: + dependency: "direct main" + description: + name: measure_size + sha256: "4b2de7b29567501434902a2f4080cf12a8bc7038b2eb97dfae91b71791620b68" + url: "https://pub.dev" + source: hosted + version: "5.0.2" media_kit: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index f124f40..ca2bb96 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,6 +63,7 @@ dependencies: media_kit: 1.2.6 media_kit_video: 2.0.1 media_kit_libs_video: 1.0.7 + measure_size: ^5.0.2 dev_dependencies: build_runner: 2.15.0