diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart index b437009..c2cb7fe 100644 --- a/lib/screens/chat/room.dart +++ b/lib/screens/chat/room.dart @@ -281,11 +281,7 @@ class _ChatRoomScreenState extends State { Expanded( child: InfiniteList( reverse: true, - padding: const EdgeInsets.only( - left: 12, - right: 12, - top: 12, - ), + padding: const EdgeInsets.only(top: 12), hasReachedMax: _messageController.isAllLoaded, itemCount: _messageController.messages.length, isLoading: _messageController.isLoading, @@ -311,23 +307,20 @@ class _ChatRoomScreenState extends State { return Align( alignment: Alignment.centerLeft, - child: Container( - constraints: BoxConstraints(maxWidth: 480), - child: ChatMessage( - data: message, - isMerged: canMerge, - hasMerged: canMergePrevious, - isPending: _messageController.unconfirmedMessages.contains(message.uuid), - onReply: (value) { - _inputGlobalKey.currentState?.setReply(value); - }, - onEdit: (value) { - _inputGlobalKey.currentState?.setEdit(value); - }, - onDelete: (value) { - _inputGlobalKey.currentState?.deleteMessage(value); - }, - ), + child: ChatMessage( + data: message, + isMerged: canMerge, + hasMerged: canMergePrevious, + isPending: _messageController.unconfirmedMessages.contains(message.uuid), + onReply: (value) { + _inputGlobalKey.currentState?.setReply(value); + }, + onEdit: (value) { + _inputGlobalKey.currentState?.setEdit(value); + }, + onDelete: (value) { + _inputGlobalKey.currentState?.deleteMessage(value); + }, ), ); }, diff --git a/lib/screens/home.dart b/lib/screens/home.dart index b990dc0..38e6cfb 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -153,9 +153,14 @@ class _HomeDashUpdateWidget extends StatelessWidget { } } -class _HomeDashSpecialDayWidget extends StatelessWidget { +class _HomeDashSpecialDayWidget extends StatefulWidget { const _HomeDashSpecialDayWidget(); + @override + State<_HomeDashSpecialDayWidget> createState() => _HomeDashSpecialDayWidgetState(); +} + +class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> { @override Widget build(BuildContext context) { final ua = context.watch(); @@ -165,21 +170,20 @@ class _HomeDashSpecialDayWidget extends StatelessWidget { if (days.isNotEmpty) { return Column( - spacing: 8, children: days.map((ele) { - return Card( - child: ListTile( - leading: Text(kSpecialDaysSymbol[ele] ?? '🎉').fontSize(24), - title: Text('celebrate$ele').tr(args: [ua.user?.nick ?? 'user']), - subtitle: Text( - DateFormat('y/M/d').format(DateTime.now().copyWith( - month: kSpecialDays[ele]?.$1, - day: kSpecialDays[ele]?.$2, - )), - ), - ), - ).padding(bottom: 8); - }).toList()); + return Card( + child: ListTile( + leading: Text(kSpecialDaysSymbol[ele] ?? '🎉').fontSize(24), + title: Text('celebrate$ele').tr(args: [ua.user?.nick ?? 'user']), + subtitle: Text( + DateFormat('y/M/d').format(DateTime.now().copyWith( + month: kSpecialDays[ele]?.$1, + day: kSpecialDays[ele]?.$2, + )), + ), + ), + ).padding(bottom: 8); + }).toList()); } final nextOne = dayz.getNextSpecialDay(); @@ -204,6 +208,9 @@ class _HomeDashSpecialDayWidget extends StatelessWidget { separatorType: SeparatorType.symbol, decoration: BoxDecoration(), padding: EdgeInsets.zero, + onDone: () { + setState(() {}); + }, ), const Gap(12), Expanded( diff --git a/lib/widgets/attachment/attachment_list.dart b/lib/widgets/attachment/attachment_list.dart index f1a0352..13966f6 100644 --- a/lib/widgets/attachment/attachment_list.dart +++ b/lib/widgets/attachment/attachment_list.dart @@ -106,76 +106,38 @@ class _AttachmentListState extends State { } if (widget.gridded) { - return Padding( - padding: widget.padding ?? EdgeInsets.zero, - child: Container( - decoration: BoxDecoration( - color: backgroundColor, - border: Border( - top: borderSide, - bottom: borderSide, - ), - borderRadius: AttachmentList.kDefaultRadius, - ), - child: ClipRRect( - borderRadius: AttachmentList.kDefaultRadius, - child: StaggeredGrid.count( - crossAxisCount: math.min(widget.data.length, 2), - crossAxisSpacing: 4, - mainAxisSpacing: 4, - children: widget.data - .mapIndexed( - (idx, ele) => GestureDetector( - child: Container( - constraints: constraints, - child: AttachmentItem( - data: ele, - heroTag: heroTags[idx], - fit: BoxFit.cover, - ), - ), - onTap: () { - if (widget.data[idx]!.mediaType != SnMediaType.image) return; - context.pushTransparentRoute( - AttachmentZoomView( - data: widget.data.where((ele) => ele != null).cast(), - initialIndex: idx, - heroTags: heroTags, - ), - backgroundColor: Colors.black.withOpacity(0.7), - rootNavigator: true, - ); - }, - ), - ) - .toList(), - ), + return Container( + margin: widget.padding ?? EdgeInsets.zero, + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + top: borderSide, + bottom: borderSide, ), + borderRadius: AttachmentList.kDefaultRadius, ), - ); - } - - return AspectRatio( - aspectRatio: (widget.data.firstOrNull?.data['ratio'] ?? 1).toDouble(), - child: Container( - constraints: BoxConstraints(maxHeight: constraints.maxHeight), - child: ScrollConfiguration( - behavior: _AttachmentListScrollBehavior(), - child: ListView.separated( - shrinkWrap: true, - itemCount: widget.data.length, - itemBuilder: (context, idx) { - return Container( - constraints: constraints, - child: AspectRatio( - aspectRatio: (widget.data[idx]?.data['ratio'] ?? 1).toDouble(), - child: GestureDetector( + child: ClipRRect( + borderRadius: AttachmentList.kDefaultRadius, + child: StaggeredGrid.count( + crossAxisCount: math.min(widget.data.length, 2), + crossAxisSpacing: 4, + mainAxisSpacing: 4, + children: widget.data + .mapIndexed( + (idx, ele) => GestureDetector( + child: Container( + constraints: constraints, + child: AttachmentItem( + data: ele, + heroTag: heroTags[idx], + fit: BoxFit.cover, + ), + ), onTap: () { - if (widget.data[idx]?.mediaType != SnMediaType.image) return; + if (widget.data[idx]!.mediaType != SnMediaType.image) return; context.pushTransparentRoute( AttachmentZoomView( - data: - widget.data.where((ele) => ele != null && ele.mediaType == SnMediaType.image).cast(), + data: widget.data.where((ele) => ele != null).cast(), initialIndex: idx, heroTags: heroTags, ), @@ -183,44 +145,76 @@ class _AttachmentListState extends State { rootNavigator: true, ); }, - child: Stack( - fit: StackFit.expand, - children: [ - Container( - decoration: BoxDecoration( - color: backgroundColor, - border: Border( - top: borderSide, - bottom: borderSide, - ), - borderRadius: AttachmentList.kDefaultRadius, + ), + ) + .toList(), + ), + ), + ); + } + + return Container( + constraints: BoxConstraints(maxHeight: constraints.maxHeight), + child: ScrollConfiguration( + behavior: _AttachmentListScrollBehavior(), + child: ListView.separated( + padding: widget.padding, + shrinkWrap: true, + itemCount: widget.data.length, + itemBuilder: (context, idx) { + return Container( + constraints: constraints.copyWith(maxWidth: widget.maxWidth), + child: AspectRatio( + aspectRatio: (widget.data[idx]?.data['ratio'] ?? 1).toDouble(), + child: GestureDetector( + onTap: () { + if (widget.data[idx]?.mediaType != SnMediaType.image) return; + context.pushTransparentRoute( + AttachmentZoomView( + data: widget.data.where((ele) => ele != null && ele.mediaType == SnMediaType.image).cast(), + initialIndex: idx, + heroTags: heroTags, + ), + backgroundColor: Colors.black.withOpacity(0.7), + rootNavigator: true, + ); + }, + child: Stack( + fit: StackFit.expand, + children: [ + Container( + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + top: borderSide, + bottom: borderSide, ), - child: ClipRRect( - borderRadius: AttachmentList.kDefaultRadius, - child: AttachmentItem( - data: widget.data[idx], - heroTag: heroTags[idx], - ), + borderRadius: AttachmentList.kDefaultRadius, + ), + child: ClipRRect( + borderRadius: AttachmentList.kDefaultRadius, + child: AttachmentItem( + data: widget.data[idx], + heroTag: heroTags[idx], ), ), - Positioned( - right: 8, - bottom: 8, - child: Chip( - label: Text('${idx + 1}/${widget.data.length}'), - ), + ), + Positioned( + right: 8, + bottom: 8, + child: Chip( + label: Text('${idx + 1}/${widget.data.length}'), ), - ], - ), + ), + ], ), ), - ); - }, - separatorBuilder: (context, index) => const Gap(8), - padding: widget.padding, - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - ), + ), + ); + }, + separatorBuilder: (context, index) => const Gap(8), + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, ), ), ); diff --git a/lib/widgets/attachment/attachment_zoom.dart b/lib/widgets/attachment/attachment_zoom.dart index f4952e7..ebd3e52 100644 --- a/lib/widgets/attachment/attachment_zoom.dart +++ b/lib/widgets/attachment/attachment_zoom.dart @@ -231,7 +231,7 @@ class _AttachmentZoomViewState extends State { children: [ IgnorePointer( child: AccountImage( - content: account!.avatar, + content: account?.avatar, radius: 19, ), ), @@ -246,7 +246,7 @@ class _AttachmentZoomViewState extends State { style: Theme.of(context).textTheme.bodySmall, ), Text( - account.nick, + account?.nick ?? 'unknown'.tr(), style: Theme.of(context).textTheme.bodyMedium, ), ], diff --git a/lib/widgets/chat/chat_message.dart b/lib/widgets/chat/chat_message.dart index 53a4b4d..1fce139 100644 --- a/lib/widgets/chat/chat_message.dart +++ b/lib/widgets/chat/chat_message.dart @@ -24,6 +24,7 @@ class ChatMessage extends StatelessWidget { final Function(SnChatMessage)? onReply; final Function(SnChatMessage)? onEdit; final Function(SnChatMessage)? onDelete; + final EdgeInsets padding; const ChatMessage({ super.key, @@ -35,6 +36,7 @@ class ChatMessage extends StatelessWidget { this.onReply, this.onEdit, this.onDelete, + this.padding = const EdgeInsets.only(left: 12, right: 12), }); @override @@ -87,83 +89,89 @@ class ChatMessage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!isMerged && !isCompact) - AccountImage( - content: user?.avatar, - ) - else if (isMerged) - const Gap(40), - const Gap(8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!isMerged) - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (isCompact) - AccountImage( - content: user?.avatar, - radius: 12, - ).padding(right: 8), - Text( - (data.sender.nick?.isNotEmpty ?? false) ? data.sender.nick! : user?.nick ?? 'unknown', - ).bold(), - const Gap(8), - Text( - dateFormatter.format(data.createdAt.toLocal()), - ).fontSize(13), - ], - ), - if (isCompact) const Gap(4), - if (data.preload?.quoteEvent != null) - StyledWidget(Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(8)), - border: Border.all( - color: Theme.of(context).dividerColor, - width: 1, + Padding( + padding: isCompact ? EdgeInsets.zero : padding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!isMerged && !isCompact) + AccountImage( + content: user?.avatar, + ) + else if (isMerged) + const Gap(40), + const Gap(8), + Expanded( + child: Container( + constraints: BoxConstraints(maxWidth: 480), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!isMerged) + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (isCompact) + AccountImage( + content: user?.avatar, + radius: 12, + ).padding(right: 8), + Text( + (data.sender.nick?.isNotEmpty ?? false) ? data.sender.nick! : user?.nick ?? 'unknown', + ).bold(), + const Gap(8), + Text( + dateFormatter.format(data.createdAt.toLocal()), + ).fontSize(13), + ], ), - ), - padding: const EdgeInsets.only( - left: 4, - right: 4, - top: 8, - bottom: 6, - ), - child: ChatMessage( - data: data.preload!.quoteEvent!, - isCompact: true, - onReply: onReply, - onEdit: onEdit, - onDelete: onDelete, - ), - )).padding(bottom: 4, top: 4), - switch (data.type) { - 'messages.new' => _ChatMessageText(data: data), - _ => _ChatMessageSystemNotify(data: data), - }, - ], - ), - ) - ], - ).opacity(isPending ? 0.5 : 1), + if (isCompact) const Gap(8), + if (data.preload?.quoteEvent != null) + StyledWidget(Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(8)), + border: Border.all( + color: Theme.of(context).dividerColor, + width: 1, + ), + ), + padding: const EdgeInsets.only( + left: 4, + right: 4, + top: 8, + bottom: 6, + ), + child: ChatMessage( + data: data.preload!.quoteEvent!, + isCompact: true, + onReply: onReply, + onEdit: onEdit, + onDelete: onDelete, + ), + )).padding(bottom: 4, top: 4), + switch (data.type) { + 'messages.new' => _ChatMessageText(data: data), + _ => _ChatMessageSystemNotify(data: data), + }, + ], + ), + ), + ) + ], + ).opacity(isPending ? 0.5 : 1), + ), if (data.body['text'] != null && data.type == 'messages.new' && (data.body['text']?.isNotEmpty ?? false)) LinkPreviewWidget(text: data.body['text']!), if (data.preload?.attachments?.isNotEmpty ?? false) AttachmentList( data: data.preload!.attachments!, bordered: true, - // gridded: true, maxHeight: 560, + maxWidth: 480, minWidth: 480, - padding: const EdgeInsets.only(top: 8), + padding: padding.copyWith(top: 8), ), - if (!hasMerged && !isCompact) const Gap(12) else if (!isCompact) const Gap(6), + if (!hasMerged && !isCompact) const Gap(12) else if (!isCompact) const Gap(8), ], ), ),