implement viewing message images
parent
e7d9f02137
commit
849e7d5067
|
@ -39,24 +39,28 @@ class ChatSetting {
|
|||
@HiveType(typeId: 1)
|
||||
class MessageT {
|
||||
@HiveField(0)
|
||||
int msgId;
|
||||
|
||||
@HiveField(1)
|
||||
String senderId;
|
||||
|
||||
@HiveField(1, defaultValue: '')
|
||||
@HiveField(2, defaultValue: '')
|
||||
String text;
|
||||
|
||||
@HiveField(2)
|
||||
@HiveField(3)
|
||||
String type;
|
||||
|
||||
@HiveField(3, defaultValue: [])
|
||||
@HiveField(4, defaultValue: [])
|
||||
List<String> attachments;
|
||||
|
||||
@HiveField(4)
|
||||
@HiveField(5)
|
||||
DateTime dateTime;
|
||||
|
||||
@HiveField(5)
|
||||
@HiveField(6)
|
||||
bool isShowTime;
|
||||
|
||||
MessageT(
|
||||
this.msgId,
|
||||
this.senderId,
|
||||
this.text,
|
||||
this.type,
|
||||
|
|
|
@ -69,30 +69,33 @@ class MessageTAdapter extends TypeAdapter<MessageT> {
|
|||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return MessageT(
|
||||
fields[0] as String,
|
||||
fields[1] == null ? '' : fields[1] as String,
|
||||
fields[2] as String,
|
||||
fields[4] as DateTime,
|
||||
fields[5] as bool,
|
||||
fields[3] == null ? [] : (fields[3] as List).cast<String>(),
|
||||
fields[0] as int,
|
||||
fields[1] as String,
|
||||
fields[2] == null ? '' : fields[2] as String,
|
||||
fields[3] as String,
|
||||
fields[5] as DateTime,
|
||||
fields[6] as bool,
|
||||
fields[4] == null ? [] : (fields[4] as List).cast<String>(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, MessageT obj) {
|
||||
writer
|
||||
..writeByte(6)
|
||||
..writeByte(7)
|
||||
..writeByte(0)
|
||||
..write(obj.senderId)
|
||||
..write(obj.msgId)
|
||||
..writeByte(1)
|
||||
..write(obj.text)
|
||||
..write(obj.senderId)
|
||||
..writeByte(2)
|
||||
..write(obj.type)
|
||||
..write(obj.text)
|
||||
..writeByte(3)
|
||||
..write(obj.attachments)
|
||||
..write(obj.type)
|
||||
..writeByte(4)
|
||||
..write(obj.dateTime)
|
||||
..write(obj.attachments)
|
||||
..writeByte(5)
|
||||
..write(obj.dateTime)
|
||||
..writeByte(6)
|
||||
..write(obj.isShowTime);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class HiveDatabase {
|
|||
if (_isInitialised) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
List<int> encryptionKeyUint8List = await _getEncryptKey();
|
||||
|
||||
await Hive.initFlutter(await getBoxDir());
|
||||
|
@ -27,7 +27,7 @@ class HiveDatabase {
|
|||
chatSettingBox.values.where((element) => element.isOpen);
|
||||
|
||||
for (var chatBox in openedChats) {
|
||||
Hive.openBox<MessageT>(
|
||||
await Hive.openBox<MessageT>(
|
||||
'message_${chatBox.contactId}',
|
||||
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
|
||||
compactionStrategy: (entries, deletedEntries) => entries > 200,
|
||||
|
@ -42,18 +42,19 @@ class HiveDatabase {
|
|||
Hive.registerAdapter(MessageTAdapter());
|
||||
}
|
||||
|
||||
static Future<void> openNewMessageBox(String contactId, int type) async {
|
||||
static Future<Box<MessageT>> openMessageBox(String contactId) async {
|
||||
final encryptionKeyUint8List = await _getEncryptKey();
|
||||
|
||||
var chatSettingBox = Hive.box<ChatSetting>('chat_setting');
|
||||
chatSettingBox.add(
|
||||
ChatSetting(contactId, type, false, false, false, DateTime.now(), 0));
|
||||
|
||||
await Hive.openBox<MessageT>(
|
||||
'message_$contactId',
|
||||
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
|
||||
compactionStrategy: (entries, deletedEntries) => entries > 200,
|
||||
);
|
||||
late Box<MessageT> messageTBox;
|
||||
try {
|
||||
messageTBox = Hive.box<MessageT>('message_$contactId');
|
||||
} catch (e) {
|
||||
messageTBox = await Hive.openBox<MessageT>(
|
||||
'message_$contactId',
|
||||
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
|
||||
compactionStrategy: (entries, deletedEntries) => entries > 200,
|
||||
);
|
||||
}
|
||||
return messageTBox;
|
||||
}
|
||||
|
||||
static Future<List<int>> _getEncryptKey() async {
|
||||
|
@ -78,60 +79,3 @@ class HiveDatabase {
|
|||
await Hive.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<void> initDatabase() async {
|
||||
// await Hive.close();
|
||||
|
||||
// List<int> encryptionKeyUint8List = await getEncryptKey();
|
||||
|
||||
// await Hive.initFlutter(await getBoxDir());
|
||||
|
||||
// Box<ChatSetting> chatSettingBox =
|
||||
// await Hive.openBox<ChatSetting>('chat_setting');
|
||||
|
||||
// final openedChats = chatSettingBox.values.where((element) => element.isOpen);
|
||||
|
||||
// for (var chatBox in openedChats) {
|
||||
// Hive.openBox<MessageT>(
|
||||
// 'message_${chatBox.contactId}',
|
||||
// encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
|
||||
// compactionStrategy: (entries, deletedEntries) => entries > 200,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// void registerAdapter() {
|
||||
// Hive.registerAdapter(ChatSettingAdapter());
|
||||
// Hive.registerAdapter(MessageTAdapter());
|
||||
// }
|
||||
|
||||
// Future<List<int>> getEncryptKey() async {
|
||||
// final id = getIt.get<UserAccount>().id;
|
||||
// const secureStorage = FlutterSecureStorage();
|
||||
// final encryptionKeyString = await secureStorage.read(key: 'encryptKey:$id');
|
||||
// if (encryptionKeyString == null) {
|
||||
// final key = Hive.generateSecureKey();
|
||||
// await secureStorage.write(
|
||||
// key: 'encryptKey:$id',
|
||||
// value: base64Encode(key),
|
||||
// );
|
||||
// }
|
||||
// String? key = await secureStorage.read(key: 'encryptKey:$id');
|
||||
// final encryptionKeyUint8List = base64Url.decode(key!);
|
||||
|
||||
// return encryptionKeyUint8List;
|
||||
// }
|
||||
|
||||
// Future<void> openNewMessageBox(String contactId, int type) async {
|
||||
// final encryptionKeyUint8List = await getEncryptKey();
|
||||
|
||||
// var chatSettingBox = Hive.box<ChatSetting>('chat_setting');
|
||||
// chatSettingBox.add(
|
||||
// ChatSetting(contactId, type, false, false, false, DateTime.now(), 0));
|
||||
|
||||
// await Hive.openBox<MessageT>(
|
||||
// 'message_$contactId',
|
||||
// encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
|
||||
// compactionStrategy: (entries, deletedEntries) => entries > 200,
|
||||
// );
|
||||
// }
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:together_mobile/database/hive_database.dart';
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
import 'package:web_socket_channel/status.dart' as status;
|
||||
|
||||
|
@ -204,14 +205,8 @@ void receiveFriendMsg(Map<String, dynamic> msg, bool isShowNotification) async {
|
|||
print(msg);
|
||||
print('=======================================');
|
||||
String senderId = msg['senderId'] as String;
|
||||
late Box<MessageT> messageTBox;
|
||||
try {
|
||||
messageTBox = Hive.box('message_$senderId');
|
||||
} catch (e) {
|
||||
messageTBox = await Hive.openBox('message_$senderId');
|
||||
}
|
||||
|
||||
Box<ChatSetting> chatSettingBox = Hive.box<ChatSetting>('chat_setting');
|
||||
Box<MessageT> messageTBox = await HiveDatabase.openMessageBox(senderId);
|
||||
ChatSetting? chatSetting = chatSettingBox.get(senderId);
|
||||
DateTime dateTime = DateTime.parse(msg['dateTime'] as String);
|
||||
|
||||
|
@ -228,8 +223,6 @@ void receiveFriendMsg(Map<String, dynamic> msg, bool isShowNotification) async {
|
|||
1,
|
||||
),
|
||||
);
|
||||
} else if ((messageTBox.get(msg['msgId'] as String)) != null) {
|
||||
return;
|
||||
} else {
|
||||
chatSetting.isOpen = true;
|
||||
chatSetting.latestDateTime = dateTime;
|
||||
|
@ -240,9 +233,9 @@ void receiveFriendMsg(Map<String, dynamic> msg, bool isShowNotification) async {
|
|||
List<String> attachments = List.from(msg['attachments']);
|
||||
final DateTime now = DateTime.parse(msg['dateTime'] as String);
|
||||
|
||||
messageTBox.put(
|
||||
msg['msgId'] as String,
|
||||
messageTBox.add(
|
||||
MessageT(
|
||||
msg['msgId'] as int,
|
||||
senderId,
|
||||
msg['text'],
|
||||
msg['type'],
|
||||
|
@ -345,14 +338,8 @@ void receiveGroupChatMsg(
|
|||
print('=======================================');
|
||||
String senderId = msg['senderId'] as String;
|
||||
String groupChatId = msg['groupChatId'] as String;
|
||||
late Box<MessageT> messageTBox;
|
||||
try {
|
||||
messageTBox = Hive.box('message_$groupChatId');
|
||||
} catch (e) {
|
||||
messageTBox = await Hive.openBox('message_$groupChatId');
|
||||
}
|
||||
|
||||
Box<ChatSetting> chatSettingBox = Hive.box<ChatSetting>('chat_setting');
|
||||
Box<MessageT> messageTBox = await HiveDatabase.openMessageBox(groupChatId);
|
||||
ChatSetting? chatSetting = chatSettingBox.get(groupChatId);
|
||||
DateTime dateTime = DateTime.parse(msg['dateTime'] as String);
|
||||
|
||||
|
@ -379,8 +366,6 @@ void receiveGroupChatMsg(
|
|||
1,
|
||||
),
|
||||
);
|
||||
} else if ((messageTBox.get(msg['msgId'] as String)) != null) {
|
||||
return;
|
||||
} else {
|
||||
chatSetting.isOpen = true;
|
||||
chatSetting.latestDateTime = dateTime;
|
||||
|
@ -391,9 +376,9 @@ void receiveGroupChatMsg(
|
|||
List<String> attachments = List.from(msg['attachments']);
|
||||
final DateTime now = DateTime.parse(msg['dateTime'] as String);
|
||||
|
||||
messageTBox.put(
|
||||
msg['msgId'] as String,
|
||||
messageTBox.add(
|
||||
MessageT(
|
||||
msg['msgId'] as int,
|
||||
senderId,
|
||||
msg['text'],
|
||||
msg['type'],
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:together_mobile/router/router_key.dart';
|
|||
import 'package:together_mobile/screens/chat/chat_screen.dart';
|
||||
import 'package:together_mobile/screens/message/friend_message_screen.dart';
|
||||
import 'package:together_mobile/screens/message/group_chat_message_screen.dart';
|
||||
import 'package:together_mobile/screens/message/image_view_screen/image_view_screen.dart';
|
||||
|
||||
final chatRouter = GoRoute(
|
||||
path: '/chat',
|
||||
|
@ -31,6 +32,24 @@ final chatRouter = GoRoute(
|
|||
);
|
||||
}
|
||||
},
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'image_view',
|
||||
name: 'ImageView',
|
||||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
Map<String, Object> extra = state.extra as Map<String, Object>;
|
||||
for (var a in extra['attachmentItems']! as List<AttachmentItem>) {
|
||||
print(a.id);
|
||||
}
|
||||
return ImageViewScreen(
|
||||
attachmentItems:
|
||||
extra['attachmentItems']! as List<AttachmentItem>,
|
||||
initialIndex: extra['index']! as int,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -4,8 +4,10 @@ import 'dart:convert';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
import 'package:together_mobile/database/box_type.dart';
|
||||
import 'package:together_mobile/database/hive_database.dart';
|
||||
import 'package:together_mobile/models/contact_model.dart';
|
||||
import 'package:together_mobile/models/init_get_it.dart';
|
||||
|
@ -196,7 +198,21 @@ class _CreateGroupChatScreenState extends State<CreateGroupChatScreen> {
|
|||
'groupGhat': res['data']
|
||||
}),
|
||||
);
|
||||
await HiveDatabase.openNewMessageBox(id, 1);
|
||||
|
||||
final chatSettingBox = Hive.box<ChatSetting>('chat_setting');
|
||||
chatSettingBox.put(
|
||||
id,
|
||||
ChatSetting(
|
||||
id,
|
||||
1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
DateTime.now(),
|
||||
0,
|
||||
),
|
||||
);
|
||||
await HiveDatabase.openMessageBox(id);
|
||||
// ignore: use_build_context_synchronously
|
||||
context.goNamed(
|
||||
'Message',
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:hive/hive.dart';
|
|||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
import 'package:together_mobile/database/box_type.dart';
|
||||
import 'package:together_mobile/database/hive_database.dart';
|
||||
|
||||
class RowFloatingButtons extends StatelessWidget {
|
||||
const RowFloatingButtons({
|
||||
|
@ -74,13 +75,7 @@ class RowFloatingButtons extends StatelessWidget {
|
|||
),
|
||||
FloatingActionButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
Hive.box<MessageT>('message_$friendId');
|
||||
} catch (e) {
|
||||
// have to await it
|
||||
await Hive.openBox<MessageT>('message_$friendId');
|
||||
}
|
||||
|
||||
HiveDatabase.openMessageBox(friendId);
|
||||
// ignore: use_build_context_synchronously
|
||||
context.pushReplacementNamed(
|
||||
'Message',
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
|
@ -11,6 +12,7 @@ import 'package:together_mobile/models/contact_model.dart';
|
|||
import 'package:together_mobile/models/init_get_it.dart';
|
||||
import 'package:together_mobile/models/user_model.dart';
|
||||
import 'package:together_mobile/request/server.dart';
|
||||
import 'package:together_mobile/screens/message/image_view_screen/image_view_screen.dart';
|
||||
|
||||
class FriendMessageBubble extends StatefulWidget {
|
||||
const FriendMessageBubble({
|
||||
|
@ -24,12 +26,14 @@ class FriendMessageBubble extends StatefulWidget {
|
|||
required this.isShowTime,
|
||||
required this.text,
|
||||
required this.attachments,
|
||||
required this.attachmentItems,
|
||||
});
|
||||
|
||||
final int index, length;
|
||||
final String contactId, senderId, type, dateTime, text;
|
||||
final bool isShowTime;
|
||||
final List<String> attachments;
|
||||
final List<AttachmentItem> attachmentItems;
|
||||
|
||||
@override
|
||||
State<FriendMessageBubble> createState() => _FriendMessageBubbleState();
|
||||
|
@ -181,6 +185,14 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
|
|||
...List.generate(
|
||||
widget.attachments.length,
|
||||
(int index) {
|
||||
int attachmentItemIndex =
|
||||
widget.attachmentItems.indexWhere(
|
||||
(element) =>
|
||||
element.resource ==
|
||||
widget.attachments[index],
|
||||
);
|
||||
int heroTagId = widget
|
||||
.attachmentItems[attachmentItemIndex].id;
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(
|
||||
bottom: 15,
|
||||
|
@ -192,14 +204,28 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
|
|||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
child: _isImagesLoaded[index]
|
||||
? Image.file(File(
|
||||
'${getIt.get<UserProfile>().baseImageDir}/${widget.attachments[index]}',
|
||||
))
|
||||
? GestureDetector(
|
||||
onTap: () {
|
||||
_onTapImage(
|
||||
context,
|
||||
widget.attachments[index],
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: heroTagId,
|
||||
child: Image.file(
|
||||
File(
|
||||
'${getIt.get<UserProfile>().baseImageDir}/${widget.attachments[index]}',
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
width: 20,
|
||||
height: 40,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10),
|
||||
vertical: 10,
|
||||
),
|
||||
child:
|
||||
const CircularProgressIndicator(
|
||||
color: kSecondaryColor,
|
||||
|
@ -234,4 +260,18 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onTapImage(BuildContext context, String attachment) {
|
||||
int attachmentIndex = widget.attachmentItems.indexWhere(
|
||||
(element) => element.resource == attachment,
|
||||
);
|
||||
|
||||
context.pushNamed(
|
||||
'ImageView',
|
||||
extra: {
|
||||
'attachmentItems': widget.attachmentItems,
|
||||
'index': attachmentIndex,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
|
@ -11,6 +12,7 @@ import 'package:together_mobile/models/contact_model.dart';
|
|||
import 'package:together_mobile/models/init_get_it.dart';
|
||||
import 'package:together_mobile/models/user_model.dart';
|
||||
import 'package:together_mobile/request/server.dart';
|
||||
import 'package:together_mobile/screens/message/image_view_screen/image_view_screen.dart';
|
||||
|
||||
class GroupChatMessageBubble extends StatefulWidget {
|
||||
const GroupChatMessageBubble({
|
||||
|
@ -24,12 +26,14 @@ class GroupChatMessageBubble extends StatefulWidget {
|
|||
required this.isShowTime,
|
||||
required this.text,
|
||||
required this.attachments,
|
||||
required this.attachmentItems,
|
||||
});
|
||||
|
||||
final int index, length;
|
||||
final String contactId, senderId, type, dateTime, text;
|
||||
final bool isShowTime;
|
||||
final List<String> attachments;
|
||||
final List<AttachmentItem> attachmentItems;
|
||||
|
||||
@override
|
||||
State<GroupChatMessageBubble> createState() => _GroupChatMessageBubbleState();
|
||||
|
@ -41,45 +45,6 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
final List<Timer> _timerList = [];
|
||||
late bool _isHideMsg;
|
||||
|
||||
// Future<bool> _getMemberGroupChatProfile() async {
|
||||
// if (widget.senderId == getIt.get<UserAccount>().id) {
|
||||
// // myself or already have profile
|
||||
// return Future(() => true);
|
||||
// }
|
||||
// if (getIt
|
||||
// .get<ContactAccountProfile>()
|
||||
// .grouChatMemberProfiles
|
||||
// .containsKey(widget.contactId) &&
|
||||
// getIt
|
||||
// .get<ContactAccountProfile>()
|
||||
// .grouChatMemberProfiles[widget.contactId]!
|
||||
// .containsKey(widget.senderId)) {
|
||||
// return Future(() => true);
|
||||
// } else {
|
||||
// Map<String, dynamic> res;
|
||||
// if (getIt.get<Contact>().friends.containsKey(widget.senderId)) {
|
||||
// // my friend
|
||||
// res = await getGroupChatMemberNameAvatar(
|
||||
// widget.contactId,
|
||||
// widget.senderId,
|
||||
// true,
|
||||
// );
|
||||
// } else {
|
||||
// res = await getGroupChatMemberNameAvatar(
|
||||
// widget.contactId,
|
||||
// widget.senderId,
|
||||
// false,
|
||||
// );
|
||||
// }
|
||||
// getIt.get<ContactAccountProfile>().addGroupChatMemberProfile(
|
||||
// widget.contactId,
|
||||
// widget.senderId,
|
||||
// res['data'],
|
||||
// );
|
||||
// return Future(() => true);
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -206,6 +171,14 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
...List.generate(
|
||||
widget.attachments.length,
|
||||
(int index) {
|
||||
int attachmentItemIndex =
|
||||
widget.attachmentItems.indexWhere(
|
||||
(element) =>
|
||||
element.resource ==
|
||||
widget.attachments[index],
|
||||
);
|
||||
int heroTagId = widget
|
||||
.attachmentItems[attachmentItemIndex].id;
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(
|
||||
bottom: 15,
|
||||
|
@ -217,9 +190,22 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
child: _isImagesLoaded[index]
|
||||
? Image.file(File(
|
||||
'${getIt.get<UserProfile>().baseImageDir}/${widget.attachments[index]}',
|
||||
))
|
||||
? GestureDetector(
|
||||
onTap: () {
|
||||
_onTapImage(
|
||||
context,
|
||||
widget.attachments[index],
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: heroTagId,
|
||||
child: Image.file(
|
||||
File(
|
||||
'${getIt.get<UserProfile>().baseImageDir}/${widget.attachments[index]}',
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
width: 20,
|
||||
height: 40,
|
||||
|
@ -255,9 +241,22 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
);
|
||||
}
|
||||
|
||||
void _onTapImage(BuildContext context, String attachment) {
|
||||
int attachmentIndex = widget.attachmentItems.indexWhere(
|
||||
(element) => element.resource == attachment,
|
||||
);
|
||||
|
||||
context.pushNamed(
|
||||
'ImageView',
|
||||
extra: {
|
||||
'attachmentItems': widget.attachmentItems,
|
||||
'index': attachmentIndex,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
CircleAvatar _showAvatar(bool isOther) {
|
||||
if (isOther) {
|
||||
print(isOther);
|
||||
String avatar = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
|
|
|
@ -239,11 +239,16 @@ class _MessageInputBoxState extends State<MessageInputBox> {
|
|||
}
|
||||
}
|
||||
|
||||
final String msgId = formatMsgIDFromTime(now);
|
||||
late int msgId;
|
||||
if (_messageTBox.length == 0) {
|
||||
msgId = 0;
|
||||
} else {
|
||||
msgId = _messageTBox.length - 1;
|
||||
}
|
||||
|
||||
_messageTBox.put(
|
||||
msgId,
|
||||
_messageTBox.add(
|
||||
MessageT(
|
||||
msgId,
|
||||
senderId,
|
||||
text,
|
||||
type,
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:together_mobile/models/route_state_model.dart';
|
|||
import 'package:together_mobile/utils/format_datetime.dart';
|
||||
import 'components/friend_message_bubble.dart';
|
||||
import 'components/message_input_box.dart';
|
||||
import 'image_view_screen/image_view_screen.dart';
|
||||
|
||||
class FriendMessageScreen extends StatefulWidget {
|
||||
const FriendMessageScreen({
|
||||
|
@ -121,8 +122,28 @@ class _FriendMessageScreenState extends State<FriendMessageScreen> {
|
|||
int i = length - index - 1;
|
||||
MessageT messageT = messageTBox.getAt(i)!;
|
||||
|
||||
List<String> allAttachments = [];
|
||||
for (var element in messageTBox.values) {
|
||||
if (element.attachments.isNotEmpty) {
|
||||
allAttachments.addAll(element.attachments);
|
||||
}
|
||||
}
|
||||
// Do not reverse the list, cause what i want is
|
||||
// rigth slide to next image, left to last otherwise
|
||||
// allAttachments = List.from(allAttachments.reversed);
|
||||
|
||||
List<AttachmentItem> attachmentItems = List.generate(
|
||||
allAttachments.length,
|
||||
(int index) {
|
||||
return AttachmentItem(
|
||||
id: index,
|
||||
resource: allAttachments[index],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return FriendMessageBubble(
|
||||
key: ValueKey(i),
|
||||
key: ValueKey(messageT.msgId),
|
||||
index: i,
|
||||
length: length,
|
||||
contactId: widget.friendId,
|
||||
|
@ -132,6 +153,7 @@ class _FriendMessageScreenState extends State<FriendMessageScreen> {
|
|||
type: messageT.type,
|
||||
text: messageT.text,
|
||||
attachments: messageT.attachments,
|
||||
attachmentItems: attachmentItems,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:together_mobile/models/route_state_model.dart';
|
|||
import 'package:together_mobile/utils/format_datetime.dart';
|
||||
import 'components/group_chat_message_bubble.dart';
|
||||
import 'components/message_input_box.dart';
|
||||
import 'image_view_screen/image_view_screen.dart';
|
||||
|
||||
class GroupChatMessageScreen extends StatefulWidget {
|
||||
const GroupChatMessageScreen({
|
||||
|
@ -135,6 +136,26 @@ class _GroupChatMessageScreenState extends State<GroupChatMessageScreen> {
|
|||
int i = length - index - 1;
|
||||
MessageT messageT = messageTBox.getAt(i)!;
|
||||
|
||||
List<String> allAttachments = [];
|
||||
for (var element in messageTBox.values) {
|
||||
if (element.attachments.isNotEmpty) {
|
||||
allAttachments.addAll(element.attachments);
|
||||
}
|
||||
}
|
||||
// Do not reverse the list, cause what i want is
|
||||
// rigth slide to next image, left to last otherwise
|
||||
// allAttachments = List.from(allAttachments.reversed);
|
||||
|
||||
List<AttachmentItem> attachmentItems = List.generate(
|
||||
allAttachments.length,
|
||||
(int index) {
|
||||
return AttachmentItem(
|
||||
id: index,
|
||||
resource: allAttachments[index],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return GroupChatMessageBubble(
|
||||
key: ValueKey(i),
|
||||
index: i,
|
||||
|
@ -146,6 +167,7 @@ class _GroupChatMessageScreenState extends State<GroupChatMessageScreen> {
|
|||
type: messageT.type,
|
||||
text: messageT.text,
|
||||
attachments: messageT.attachments,
|
||||
attachmentItems: attachmentItems,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:photo_view/photo_view_gallery.dart';
|
||||
import 'package:together_mobile/models/init_get_it.dart';
|
||||
import 'package:together_mobile/models/user_model.dart';
|
||||
|
||||
// https://github.com/bluefireteam/photo_view/blob/main/example/lib/screens/examples/gallery/gallery_example.dart
|
||||
|
||||
class AttachmentItem {
|
||||
AttachmentItem({
|
||||
required this.id,
|
||||
required this.resource,
|
||||
});
|
||||
|
||||
final int id;
|
||||
final String resource;
|
||||
}
|
||||
|
||||
class ImageViewScreen extends StatefulWidget {
|
||||
ImageViewScreen({
|
||||
super.key,
|
||||
this.loadingBuilder,
|
||||
this.minScale,
|
||||
this.maxScale,
|
||||
this.initialIndex = 0,
|
||||
required this.attachmentItems,
|
||||
this.scrollDirection = Axis.horizontal,
|
||||
}) : pageController = PageController(initialPage: initialIndex);
|
||||
|
||||
final LoadingBuilder? loadingBuilder;
|
||||
final dynamic minScale;
|
||||
final dynamic maxScale;
|
||||
final int initialIndex;
|
||||
final PageController pageController;
|
||||
final List<AttachmentItem> attachmentItems;
|
||||
final Axis scrollDirection;
|
||||
|
||||
@override
|
||||
State<ImageViewScreen> createState() => _ImageViewScreenState();
|
||||
}
|
||||
|
||||
class _ImageViewScreenState extends State<ImageViewScreen> {
|
||||
late int currentIndex = widget.initialIndex;
|
||||
|
||||
void onPageChanged(int index) {
|
||||
setState(() {
|
||||
currentIndex = index;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: GestureDetector(
|
||||
onTap: () {
|
||||
context.pop();
|
||||
},
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(color: Colors.black),
|
||||
constraints: BoxConstraints.expand(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: <Widget>[
|
||||
PhotoViewGallery.builder(
|
||||
scrollPhysics: const BouncingScrollPhysics(),
|
||||
builder: _buildItem,
|
||||
itemCount: widget.attachmentItems.length,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
backgroundDecoration: const BoxDecoration(color: Colors.black),
|
||||
pageController: widget.pageController,
|
||||
onPageChanged: onPageChanged,
|
||||
scrollDirection: widget.scrollDirection,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Text(
|
||||
"Image ${currentIndex + 1}",
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 17.0,
|
||||
decoration: null,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
|
||||
final AttachmentItem item = widget.attachmentItems[index];
|
||||
return PhotoViewGalleryPageOptions(
|
||||
imageProvider: FileImage(
|
||||
File('${getIt.get<UserProfile>().baseImageDir}/${item.resource}'),
|
||||
),
|
||||
initialScale: PhotoViewComputedScale.contained,
|
||||
minScale: PhotoViewComputedScale.contained * (0.5 + index / 10),
|
||||
maxScale: PhotoViewComputedScale.covered * 4.1,
|
||||
heroAttributes: PhotoViewHeroAttributes(tag: item.id),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ class SettingScreen extends StatelessWidget {
|
|||
getIt.get<ApplyList>().clear();
|
||||
getIt.get<Contact>().clear();
|
||||
getIt.get<ContactAccountProfile>().clear();
|
||||
// Hive.deleteFromDisk();
|
||||
Hive.deleteFromDisk();
|
||||
await HiveDatabase.close();
|
||||
},
|
||||
);
|
||||
|
|
434
pubspec.lock
434
pubspec.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue