mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 13:52:12 +00:00
small redesign of the image view
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
68c99c271f
commit
32231d11c2
9 changed files with 132 additions and 163 deletions
|
|
@ -441,6 +441,9 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
await mc.cameraController!.setZoomLevel(
|
||||
mc.selectedCameraDetails.scaleFactor,
|
||||
);
|
||||
if (!userService.currentUser.hasZoomed) {
|
||||
await UserService.update((u) => u.hasZoomed = true);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> pickImageFromGallery() async {
|
||||
|
|
@ -613,12 +616,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
if (mounted) showSnackbar(context, 'Error: $e');
|
||||
}
|
||||
|
||||
void _incrementZoomUsageCount() {
|
||||
if (!userService.currentUser.hasZoomed) {
|
||||
UserService.update((u) => u.hasZoomed = true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
|
||||
|
|
@ -666,19 +663,9 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
},
|
||||
onLongPressEnd: (a) {
|
||||
stopVideoRecording();
|
||||
if ((mc.selectedCameraDetails.scaleFactor - _baseScaleFactor)
|
||||
.abs() >
|
||||
0.05) {
|
||||
_incrementZoomUsageCount();
|
||||
}
|
||||
},
|
||||
onPanEnd: (a) {
|
||||
stopVideoRecording();
|
||||
if ((mc.selectedCameraDetails.scaleFactor - _baseScaleFactor)
|
||||
.abs() >
|
||||
0.05) {
|
||||
_incrementZoomUsageCount();
|
||||
}
|
||||
},
|
||||
onPanUpdate: onPanUpdate,
|
||||
child: Stack(
|
||||
|
|
|
|||
|
|
@ -101,15 +101,16 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
Widget? _getChatEntry(BorderRadius borderRadius, int reactionsForWidth) {
|
||||
Widget? _getChatEntry(
|
||||
BorderRadius borderRadius,
|
||||
int reactionsForWidth,
|
||||
BubbleInfo info,
|
||||
) {
|
||||
if (widget.message.type == MessageType.text.name) {
|
||||
return ChatTextEntry(
|
||||
message: widget.message,
|
||||
nextMessage: widget.nextMessage,
|
||||
prevMessage: widget.prevMessage,
|
||||
userIdToContact: widget.userIdToContact,
|
||||
borderRadius: borderRadius,
|
||||
minWidth: reactionsForWidth * 43,
|
||||
info: info,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -118,12 +119,9 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
if (mediaService!.mediaFile.type == MediaType.audio) {
|
||||
return ChatAudioEntry(
|
||||
message: widget.message,
|
||||
nextMessage: widget.nextMessage,
|
||||
prevMessage: widget.prevMessage,
|
||||
mediaService: mediaService!,
|
||||
userIdToContact: widget.userIdToContact,
|
||||
borderRadius: borderRadius,
|
||||
minWidth: reactionsForWidth * 43,
|
||||
info: info,
|
||||
);
|
||||
}
|
||||
return ChatMediaEntry(
|
||||
|
|
@ -131,7 +129,8 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
group: widget.group,
|
||||
mediaService: mediaService!,
|
||||
galleryItems: widget.galleryItems,
|
||||
minWidth: reactionsForWidth * 43,
|
||||
borderRadius: borderRadius,
|
||||
info: info,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -168,6 +167,15 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
.length;
|
||||
if (reactionsForWidth > 4) reactionsForWidth = 4;
|
||||
|
||||
final info = getBubbleInfo(
|
||||
context,
|
||||
widget.message,
|
||||
widget.nextMessage,
|
||||
widget.prevMessage,
|
||||
widget.userIdToContact,
|
||||
reactionsForWidth * 43.0,
|
||||
);
|
||||
|
||||
Widget child = Stack(
|
||||
// overflow: Overflow.visible,
|
||||
// clipBehavior: Clip.none,
|
||||
|
|
@ -176,11 +184,8 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
if (widget.message.isDeletedFromSender)
|
||||
ChatTextEntry(
|
||||
message: widget.message,
|
||||
nextMessage: widget.nextMessage,
|
||||
prevMessage: widget.prevMessage,
|
||||
userIdToContact: widget.userIdToContact,
|
||||
borderRadius: borderRadius,
|
||||
minWidth: reactionsForWidth * 43,
|
||||
info: info,
|
||||
)
|
||||
else
|
||||
Column(
|
||||
|
|
@ -191,7 +196,7 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
|||
mediaService: mediaService,
|
||||
borderRadius: borderRadius,
|
||||
scrollToMessage: widget.scrollToMessage,
|
||||
child: _getChatEntry(borderRadius, reactionsForWidth),
|
||||
child: _getChatEntry(borderRadius, reactionsForWidth, info),
|
||||
),
|
||||
if (reactionsForWidth > 0) const SizedBox(height: 20, width: 10),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -13,22 +13,16 @@ import 'package:twonly/src/visual/views/chats/chat_messages_components/message_s
|
|||
class ChatAudioEntry extends StatelessWidget {
|
||||
const ChatAudioEntry({
|
||||
required this.message,
|
||||
required this.nextMessage,
|
||||
required this.mediaService,
|
||||
required this.prevMessage,
|
||||
required this.borderRadius,
|
||||
required this.userIdToContact,
|
||||
required this.minWidth,
|
||||
required this.info,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Message message;
|
||||
final MediaFileService mediaService;
|
||||
final Message? nextMessage;
|
||||
final Message? prevMessage;
|
||||
final Map<int, Contact>? userIdToContact;
|
||||
final BorderRadius borderRadius;
|
||||
final double minWidth;
|
||||
final BubbleInfo info;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -36,14 +30,6 @@ class ChatAudioEntry extends StatelessWidget {
|
|||
!mediaService.originalPath.existsSync()) {
|
||||
return Container(); // media file was purged
|
||||
}
|
||||
final info = getBubbleInfo(
|
||||
context,
|
||||
message,
|
||||
nextMessage,
|
||||
prevMessage,
|
||||
userIdToContact,
|
||||
minWidth,
|
||||
);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
|
|
@ -63,12 +49,7 @@ class ChatAudioEntry extends StatelessWidget {
|
|||
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
||||
minWidth: 250,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
top: 6,
|
||||
bottom: 6,
|
||||
right: 10,
|
||||
),
|
||||
padding: info.padding,
|
||||
decoration: BoxDecoration(
|
||||
color: info.color,
|
||||
borderRadius: borderRadius,
|
||||
|
|
|
|||
|
|
@ -26,15 +26,17 @@ class ChatMediaEntry extends StatefulWidget {
|
|||
required this.group,
|
||||
required this.galleryItems,
|
||||
required this.mediaService,
|
||||
required this.minWidth,
|
||||
required this.borderRadius,
|
||||
required this.info,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Message message;
|
||||
final double minWidth;
|
||||
final Group group;
|
||||
final List<MemoryItem> galleryItems;
|
||||
final MediaFileService mediaService;
|
||||
final BorderRadius borderRadius;
|
||||
final BubbleInfo info;
|
||||
|
||||
@override
|
||||
State<ChatMediaEntry> createState() => _ChatMediaEntryState();
|
||||
|
|
@ -116,52 +118,34 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
|||
context,
|
||||
);
|
||||
|
||||
var imageBorderRadius = BorderRadius.circular(12);
|
||||
var imageBorderRadius = widget.borderRadius;
|
||||
|
||||
Widget additionalMessageData = Container();
|
||||
|
||||
final addData = widget.message.additionalMessageData;
|
||||
if (addData != null) {
|
||||
final info = getBubbleInfo(
|
||||
context,
|
||||
widget.message,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
200,
|
||||
);
|
||||
final data = AdditionalMessageData.fromBuffer(addData);
|
||||
if (data.hasLink() && widget.message.mediaStored) {
|
||||
imageBorderRadius = const BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
bottomLeft: Radius.circular(5),
|
||||
bottomRight: Radius.circular(5),
|
||||
imageBorderRadius = widget.borderRadius.copyWith(
|
||||
bottomLeft: const Radius.circular(5),
|
||||
bottomRight: const Radius.circular(5),
|
||||
);
|
||||
|
||||
additionalMessageData = Container(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
top: 6,
|
||||
bottom: 6,
|
||||
right: 10,
|
||||
),
|
||||
padding: widget.info.padding,
|
||||
decoration: BoxDecoration(
|
||||
color: info.color,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(5),
|
||||
topRight: Radius.circular(12),
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
color: widget.info.color,
|
||||
borderRadius: widget.borderRadius.copyWith(
|
||||
topLeft: const Radius.circular(5),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
BetterText(text: data.link, textColor: info.textColor),
|
||||
BetterText(text: data.link, textColor: widget.info.textColor),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
@ -178,7 +162,12 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
|||
onDoubleTap: onDoubleTap,
|
||||
onTap: (widget.message.type == MessageType.media.name) ? onTap : null,
|
||||
child: SizedBox(
|
||||
width: (widget.minWidth > 150) ? widget.minWidth : 150,
|
||||
width: (widget.info.minWidth > 150)
|
||||
? widget.info.minWidth
|
||||
: (widget.message.mediaStored &&
|
||||
widget.mediaService.imagePreviewAvailable)
|
||||
? 150
|
||||
: null,
|
||||
height:
|
||||
(widget.message.mediaStored &&
|
||||
widget.mediaService.imagePreviewAvailable)
|
||||
|
|
@ -195,6 +184,8 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
|||
color: color,
|
||||
galleryItems: widget.galleryItems,
|
||||
canBeReopened: _canBeReopened,
|
||||
borderRadius: imageBorderRadius,
|
||||
info: widget.info,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8,20 +8,14 @@ import 'package:twonly/src/visual/views/chats/chat_messages_components/entries/f
|
|||
class ChatTextEntry extends StatelessWidget {
|
||||
const ChatTextEntry({
|
||||
required this.message,
|
||||
required this.nextMessage,
|
||||
required this.prevMessage,
|
||||
required this.borderRadius,
|
||||
required this.userIdToContact,
|
||||
required this.minWidth,
|
||||
required this.info,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Message message;
|
||||
final Message? nextMessage;
|
||||
final Message? prevMessage;
|
||||
final Map<int, Contact>? userIdToContact;
|
||||
final BorderRadius borderRadius;
|
||||
final double minWidth;
|
||||
final BubbleInfo info;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -40,15 +34,6 @@ class ChatTextEntry extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
final info = getBubbleInfo(
|
||||
context,
|
||||
message,
|
||||
nextMessage,
|
||||
prevMessage,
|
||||
userIdToContact,
|
||||
minWidth,
|
||||
);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final textWidth = measureTextWidth(info.text);
|
||||
|
|
@ -65,14 +50,9 @@ class ChatTextEntry extends StatelessWidget {
|
|||
return Container(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
||||
minWidth: minWidth,
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
top: 6,
|
||||
bottom: 6,
|
||||
right: 10,
|
||||
minWidth: info.minWidth,
|
||||
),
|
||||
padding: info.padding,
|
||||
decoration: BoxDecoration(
|
||||
color: info.color,
|
||||
borderRadius: borderRadius,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class BubbleInfo {
|
|||
late Color color;
|
||||
late bool expanded;
|
||||
late double spacerWidth;
|
||||
late EdgeInsets padding;
|
||||
late double minWidth;
|
||||
}
|
||||
|
||||
BubbleInfo getBubbleInfo(
|
||||
|
|
@ -29,7 +31,11 @@ BubbleInfo getBubbleInfo(
|
|||
..textColor = Colors.white
|
||||
..color = getMessageColor(message.senderId != null)
|
||||
..displayTime = !combineTextMessageWithNext(message, nextMessage)
|
||||
..displayUserName = '';
|
||||
..displayUserName = ''
|
||||
..minWidth = minWidth
|
||||
..padding = message.type == MessageType.media.name
|
||||
? const EdgeInsets.symmetric(horizontal: 10, vertical: 2)
|
||||
: const EdgeInsets.only(left: 10, top: 6, bottom: 6, right: 10);
|
||||
|
||||
if (message.senderId != null &&
|
||||
userIdToContact != null &&
|
||||
|
|
@ -86,11 +92,10 @@ double measureTextWidth(
|
|||
}
|
||||
|
||||
bool combineTextMessageWithNext(Message message, Message? nextMessage) {
|
||||
if (nextMessage != null && nextMessage.content != null) {
|
||||
if (nextMessage != null) {
|
||||
if (nextMessage.senderId == message.senderId) {
|
||||
if (nextMessage.type == MessageType.text.name &&
|
||||
message.type == MessageType.text.name) {
|
||||
if (!EmojiAnimationComp.supported(nextMessage.content!)) {
|
||||
if (nextMessage.content == null ||
|
||||
!EmojiAnimationComp.supported(nextMessage.content!)) {
|
||||
final diff = nextMessage.createdAt
|
||||
.difference(message.createdAt)
|
||||
.inMinutes;
|
||||
|
|
@ -100,6 +105,5 @@ bool combineTextMessageWithNext(Message message, Message? nextMessage) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,17 +6,21 @@ import 'package:twonly/src/database/twonly.db.dart';
|
|||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
||||
class FriendlyMessageTime extends StatelessWidget {
|
||||
const FriendlyMessageTime({required this.message, super.key});
|
||||
const FriendlyMessageTime({
|
||||
required this.message,
|
||||
this.color,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Message message;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: AlignmentGeometry.centerRight,
|
||||
child: Padding(
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 6),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (message.modifiedAt != null && !message.isDeletedFromSender)
|
||||
Padding(
|
||||
|
|
@ -25,7 +29,7 @@ class FriendlyMessageTime extends StatelessWidget {
|
|||
height: 10,
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.pencil,
|
||||
color: Colors.white.withAlpha(150),
|
||||
color: color ?? Colors.white.withAlpha(150),
|
||||
size: 10,
|
||||
),
|
||||
),
|
||||
|
|
@ -39,14 +43,13 @@ class FriendlyMessageTime extends StatelessWidget {
|
|||
),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.white.withAlpha(150),
|
||||
color: color ?? Colors.white.withAlpha(150),
|
||||
decoration: TextDecoration.none,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import 'package:twonly/locator.dart';
|
|||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/model/memory_item.model.dart';
|
||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/visual/views/chats/chat_messages_components/entries/common.dart';
|
||||
import 'package:twonly/src/visual/views/chats/chat_messages_components/entries/friendly_message_time.comp.dart';
|
||||
import 'package:twonly/src/visual/views/chats/chat_messages_components/message_send_state_icon.dart';
|
||||
import 'package:twonly/src/visual/views/memories/components/memory_thumbnail.comp.dart';
|
||||
import 'package:twonly/src/visual/views/memories/synchronized_viewer.view.dart';
|
||||
|
|
@ -17,6 +20,8 @@ class InChatMediaViewer extends StatefulWidget {
|
|||
required this.color,
|
||||
required this.galleryItems,
|
||||
required this.canBeReopened,
|
||||
required this.borderRadius,
|
||||
required this.info,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -26,6 +31,8 @@ class InChatMediaViewer extends StatefulWidget {
|
|||
final List<MemoryItem> galleryItems;
|
||||
final Color color;
|
||||
final bool canBeReopened;
|
||||
final BorderRadius borderRadius;
|
||||
final BubbleInfo info;
|
||||
|
||||
@override
|
||||
State<InChatMediaViewer> createState() => _InChatMediaViewerState();
|
||||
|
|
@ -147,22 +154,33 @@ class _InChatMediaViewerState extends State<InChatMediaViewer> {
|
|||
minHeight: 39,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.info.color.withValues(alpha: 0.3),
|
||||
border: Border.all(
|
||||
color: widget.color,
|
||||
color: widget.info.color.withValues(alpha: 0.4),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: widget.borderRadius,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: (widget.canBeReopened) ? 5 : 10.0,
|
||||
horizontal: 4,
|
||||
),
|
||||
child: MessageSendStateIcon(
|
||||
padding: widget.info.padding,
|
||||
child: Row(
|
||||
children: [
|
||||
MessageSendStateIcon(
|
||||
[widget.message],
|
||||
[widget.mediaService.mediaFile],
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: widget.message.senderId == null
|
||||
? MainAxisAlignment.end
|
||||
: MainAxisAlignment.start,
|
||||
canBeReopened: widget.canBeReopened,
|
||||
),
|
||||
if (widget.info.displayTime || widget.message.modifiedAt != null)
|
||||
FriendlyMessageTime(
|
||||
message: widget.message,
|
||||
color: isDarkMode(context)
|
||||
? Colors.white.withAlpha(100)
|
||||
: Colors.black.withAlpha(100),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -172,7 +190,7 @@ class _InChatMediaViewerState extends State<InChatMediaViewer> {
|
|||
color: Colors.transparent,
|
||||
),
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: widget.borderRadius,
|
||||
),
|
||||
child: galleryItemIndex != null
|
||||
? MemoriesThumbnailComp(
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ class MemoriesViewState extends State<MemoriesView> {
|
|||
strokeWidth: 2.5,
|
||||
color: context.color.primary,
|
||||
backgroundColor: context.color.primary
|
||||
.withOpacity(0.2),
|
||||
.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue