Merge branch 'feature/new-ui' into qa-fix-dj
This commit is contained in:
@@ -31,15 +31,15 @@ android {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
disable 'InvalidPackage'
|
disable 'InvalidPackage'
|
||||||
|
checkReleaseBuilds false
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.example.example"
|
applicationId "com.example.example"
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath 'com.google.gms:google-services:4.3.2'
|
classpath 'com.google.gms:google-services:4.3.2'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ PODS:
|
|||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_apns (0.0.1):
|
- flutter_apns (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- flutter_app_badger (0.0.1):
|
||||||
|
- Flutter
|
||||||
- flutter_keyboard_visibility (0.0.1):
|
- flutter_keyboard_visibility (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_local_notifications (0.0.1):
|
- flutter_local_notifications (0.0.1):
|
||||||
@@ -160,6 +162,7 @@ DEPENDENCIES:
|
|||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_apns (from `.symlinks/plugins/flutter_apns/ios`)
|
- flutter_apns (from `.symlinks/plugins/flutter_apns/ios`)
|
||||||
|
- flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`)
|
||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||||
@@ -207,6 +210,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_apns:
|
flutter_apns:
|
||||||
:path: ".symlinks/plugins/flutter_apns/ios"
|
:path: ".symlinks/plugins/flutter_apns/ios"
|
||||||
|
flutter_app_badger:
|
||||||
|
:path: ".symlinks/plugins/flutter_app_badger/ios"
|
||||||
flutter_keyboard_visibility:
|
flutter_keyboard_visibility:
|
||||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
@@ -244,6 +249,7 @@ SPEC CHECKSUMS:
|
|||||||
FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44
|
FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44
|
||||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||||
flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f
|
flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f
|
||||||
|
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
|
||||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||||
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
|
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
|
|||||||
@@ -322,6 +322,7 @@
|
|||||||
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
|
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_apns/flutter_apns.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_apns/flutter_apns.framework",
|
||||||
|
"${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
|
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
|
||||||
@@ -350,6 +351,7 @@
|
|||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_apns.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_apns.framework",
|
||||||
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
|
||||||
|
|||||||
@@ -54,5 +54,9 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>remote-notification</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ void main() async {
|
|||||||
|
|
||||||
await client.setUser(
|
await client.setUser(
|
||||||
User(id: 'super-band-9', extraData: {
|
User(id: 'super-band-9', extraData: {
|
||||||
'name': 'John Doe',
|
'name': 'Jonathan Doe',
|
||||||
}),
|
}),
|
||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: example
|
name: example
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
version: 1.0.32+34
|
version: 1.0.36+38
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.2.2 <3.0.0"
|
sdk: ">=2.2.2 <3.0.0"
|
||||||
|
|||||||
@@ -43,88 +43,102 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
final ownId = StreamChat.of(context).user.id;
|
||||||
children: [
|
return GestureDetector(
|
||||||
Positioned.fill(
|
behavior: HitTestBehavior.translucent,
|
||||||
child: GestureDetector(
|
onTap: () {
|
||||||
behavior: HitTestBehavior.translucent,
|
Navigator.pop(context);
|
||||||
onTap: () {
|
},
|
||||||
Navigator.pop(context);
|
child: Stack(
|
||||||
},
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(
|
filter: ImageFilter.blur(
|
||||||
sigmaX: 10,
|
sigmaX: 10.8731,
|
||||||
sigmaY: 10,
|
sigmaY: 10.8731,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.black.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Center(
|
||||||
Column(
|
child: SingleChildScrollView(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
children: <Widget>[
|
|
||||||
if (showReactions &&
|
|
||||||
(message.status == MessageSendingStatus.SENT ||
|
|
||||||
message.status == null))
|
|
||||||
Center(
|
|
||||||
child: ReactionPicker(
|
|
||||||
message: message,
|
|
||||||
messageTheme: messageTheme,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
AbsorbPointer(
|
|
||||||
child: MessageWidget(
|
|
||||||
key: Key('MessageWidget'),
|
|
||||||
reverse: reverse,
|
|
||||||
message: message.text.length > 200
|
|
||||||
? message.copyWith(
|
|
||||||
text: '${message.text.substring(0, 200)}...')
|
|
||||||
: message,
|
|
||||||
messageTheme: messageTheme,
|
|
||||||
showReactions: false,
|
|
||||||
showUsername: false,
|
|
||||||
showReplyIndicator: false,
|
|
||||||
showTimestamp: false,
|
|
||||||
showSendingIndicator: DisplayWidget.gone,
|
|
||||||
shape: messageShape,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 48.0,
|
|
||||||
),
|
|
||||||
child: Material(
|
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: ListTile.divideTiles(
|
children: <Widget>[
|
||||||
context: context,
|
if (showReactions &&
|
||||||
tiles: [
|
(message.status == MessageSendingStatus.SENT ||
|
||||||
if (showReply &&
|
message.status == null))
|
||||||
(message.status == MessageSendingStatus.SENT ||
|
Center(
|
||||||
message.status == null) &&
|
child: ReactionPicker(
|
||||||
message.parentId == null)
|
message: message,
|
||||||
_buildReplyButton(context),
|
messageTheme: messageTheme,
|
||||||
if (showEditMessage) _buildEditMessage(context),
|
),
|
||||||
if (showDeleteMessage) _buildDeleteButton(context),
|
),
|
||||||
if (showCopyMessage) _buildCopyButton(context),
|
IgnorePointer(
|
||||||
],
|
child: MessageWidget(
|
||||||
).toList(),
|
key: Key('MessageWidget'),
|
||||||
|
reverse: reverse,
|
||||||
|
message: message.copyWith(
|
||||||
|
text: message.text.length > 200
|
||||||
|
? '${message.text.substring(0, 200)}...'
|
||||||
|
: message.text,
|
||||||
|
),
|
||||||
|
messageTheme: messageTheme,
|
||||||
|
showReactions: false,
|
||||||
|
showUsername: false,
|
||||||
|
showReplyIndicator: false,
|
||||||
|
showUserAvatar: message.user.id == ownId
|
||||||
|
? DisplayWidget.gone
|
||||||
|
: DisplayWidget.show,
|
||||||
|
showTimestamp: false,
|
||||||
|
showSendingIndicator: DisplayWidget.gone,
|
||||||
|
shape: messageShape,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 48.0,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: ListTile.divideTiles(
|
||||||
|
context: context,
|
||||||
|
tiles: [
|
||||||
|
if (showReply &&
|
||||||
|
(message.status ==
|
||||||
|
MessageSendingStatus.SENT ||
|
||||||
|
message.status == null) &&
|
||||||
|
message.parentId == null)
|
||||||
|
_buildReplyButton(context),
|
||||||
|
if (showEditMessage) _buildEditMessage(context),
|
||||||
|
if (showDeleteMessage)
|
||||||
|
_buildDeleteButton(context),
|
||||||
|
if (showCopyMessage) _buildCopyButton(context),
|
||||||
|
],
|
||||||
|
).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,66 +34,75 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
final ownId = StreamChat.of(context).user.id;
|
||||||
children: [
|
return GestureDetector(
|
||||||
Positioned.fill(
|
behavior: HitTestBehavior.translucent,
|
||||||
child: GestureDetector(
|
onTap: () {
|
||||||
behavior: HitTestBehavior.translucent,
|
Navigator.pop(context);
|
||||||
onTap: () {
|
},
|
||||||
Navigator.pop(context);
|
child: Stack(
|
||||||
},
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(
|
filter: ImageFilter.blur(
|
||||||
sigmaX: 10,
|
sigmaX: 10.8731,
|
||||||
sigmaY: 10,
|
sigmaY: 10.8731,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.black.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Center(
|
||||||
Column(
|
child: SingleChildScrollView(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
children: <Widget>[
|
child: Column(
|
||||||
if (showReactions &&
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
(message.status == MessageSendingStatus.SENT ||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
message.status == null))
|
children: <Widget>[
|
||||||
Center(
|
if (showReactions &&
|
||||||
child: ReactionPicker(
|
(message.status == MessageSendingStatus.SENT ||
|
||||||
message: message,
|
message.status == null))
|
||||||
messageTheme: messageTheme,
|
Center(
|
||||||
|
child: ReactionPicker(
|
||||||
|
message: message,
|
||||||
|
messageTheme: messageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IgnorePointer(
|
||||||
|
child: MessageWidget(
|
||||||
|
key: Key('MessageWidget'),
|
||||||
|
reverse: reverse,
|
||||||
|
message: message.copyWith(
|
||||||
|
text: message.text.length > 200
|
||||||
|
? '${message.text.substring(0, 200)}...'
|
||||||
|
: message.text,
|
||||||
|
),
|
||||||
|
messageTheme: messageTheme,
|
||||||
|
showReactions: false,
|
||||||
|
showUsername: false,
|
||||||
|
showUserAvatar: message.user.id == ownId
|
||||||
|
? DisplayWidget.gone
|
||||||
|
: DisplayWidget.show,
|
||||||
|
showReplyIndicator: false,
|
||||||
|
showTimestamp: false,
|
||||||
|
showSendingIndicator: DisplayWidget.gone,
|
||||||
|
shape: messageShape,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
if (message.latestReactions?.isNotEmpty == true)
|
||||||
|
_buildReactionCard(context),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
AbsorbPointer(
|
|
||||||
child: MessageWidget(
|
|
||||||
key: Key('MessageWidget'),
|
|
||||||
reverse: reverse,
|
|
||||||
message: message.text.length > 200
|
|
||||||
? message.copyWith(
|
|
||||||
text: '${message.text.substring(0, 200)}...')
|
|
||||||
: message,
|
|
||||||
messageTheme: messageTheme,
|
|
||||||
showReactions: false,
|
|
||||||
showUsername: false,
|
|
||||||
showReplyIndicator: false,
|
|
||||||
showTimestamp: false,
|
|
||||||
showSendingIndicator: DisplayWidget.gone,
|
|
||||||
shape: messageShape,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
height: 16,
|
],
|
||||||
),
|
),
|
||||||
if (message.latestReactions?.isNotEmpty == true)
|
|
||||||
Container(
|
|
||||||
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
|
||||||
child: _buildReactionCard(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,30 +128,25 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Padding(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(
|
child: Padding(
|
||||||
left: 16.0,
|
padding: const EdgeInsets.only(
|
||||||
right: 16,
|
left: 18,
|
||||||
bottom: 16,
|
right: 18,
|
||||||
),
|
bottom: 26,
|
||||||
child: GridView.builder(
|
),
|
||||||
shrinkWrap: true,
|
child: Wrap(
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
spacing: 16,
|
||||||
crossAxisCount: 4,
|
runSpacing: 22,
|
||||||
crossAxisSpacing: 16,
|
alignment: WrapAlignment.start,
|
||||||
childAspectRatio: 0.75,
|
children: message.latestReactions
|
||||||
mainAxisSpacing: 22,
|
.map((e) => _buildReaction(
|
||||||
|
e,
|
||||||
|
currentUser,
|
||||||
|
context,
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
itemCount: message.latestReactions.length,
|
|
||||||
itemBuilder: (context, i) {
|
|
||||||
final reaction = message.latestReactions[i];
|
|
||||||
|
|
||||||
return _buildReaction(
|
|
||||||
reaction,
|
|
||||||
currentUser,
|
|
||||||
context,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -152,51 +156,56 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Column _buildReaction(
|
Widget _buildReaction(
|
||||||
Reaction reaction,
|
Reaction reaction,
|
||||||
User currentUser,
|
User currentUser,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
final isCurrentUser = reaction.user.id == currentUser.id;
|
final isCurrentUser = reaction.user.id == currentUser.id;
|
||||||
return Column(
|
return ConstrainedBox(
|
||||||
mainAxisSize: MainAxisSize.min,
|
constraints: BoxConstraints.loose(Size(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
64,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
98,
|
||||||
children: [
|
)),
|
||||||
Stack(
|
child: Column(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
UserAvatar(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
onTap: onUserAvatarTap,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
user: reaction.user,
|
children: [
|
||||||
constraints: BoxConstraints.tightFor(
|
Stack(
|
||||||
height: 64,
|
children: [
|
||||||
width: 64,
|
UserAvatar(
|
||||||
|
onTap: onUserAvatarTap,
|
||||||
|
user: reaction.user,
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 64,
|
||||||
|
width: 64,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(32),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(32),
|
Positioned(
|
||||||
),
|
child: Align(
|
||||||
Positioned(
|
alignment: Alignment.centerLeft,
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
reactions: [reaction],
|
reactions: [reaction],
|
||||||
borderColor: isCurrentUser
|
borderColor: messageTheme.reactionsBorderColor,
|
||||||
? messageTheme.ownReactionsBorderColor
|
backgroundColor: messageTheme.reactionsBackgroundColor,
|
||||||
: messageTheme.otherReactionsBorderColor,
|
highlightOwnReactions: false,
|
||||||
backgroundColor: isCurrentUser
|
),
|
||||||
? messageTheme.ownReactionsBackgroundColor
|
),
|
||||||
: messageTheme.otherReactionsBackgroundColor,
|
bottom: 4,
|
||||||
flipTail: !isCurrentUser,
|
left: isCurrentUser ? 0 : null,
|
||||||
|
right: isCurrentUser ? 0 : null,
|
||||||
),
|
),
|
||||||
bottom: 0,
|
],
|
||||||
left: isCurrentUser ? 0 : null,
|
),
|
||||||
right: isCurrentUser ? 0 : null,
|
Text(
|
||||||
),
|
reaction.user.name,
|
||||||
],
|
style: Theme.of(context).textTheme.subtitle2,
|
||||||
),
|
textAlign: TextAlign.center,
|
||||||
Text(
|
),
|
||||||
reaction.user.name,
|
],
|
||||||
style: Theme.of(context).textTheme.subtitle2,
|
),
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class MessageText extends StatelessWidget {
|
|||||||
final text = _replaceMentions(message.text);
|
final text = _replaceMentions(message.text);
|
||||||
return MarkdownBody(
|
return MarkdownBody(
|
||||||
data: text,
|
data: text,
|
||||||
onTapLink: (link) {
|
onTapLink: (text, link, title) {
|
||||||
if (link.startsWith('@')) {
|
if (link.startsWith('@')) {
|
||||||
final mentionedUser = message.mentionedUsers.firstWhere(
|
final mentionedUser = message.mentionedUsers.firstWhere(
|
||||||
(u) => '@${u.name.replaceAll(' ', '')}' == link,
|
(u) => '@${u.name.replaceAll(' ', '')}' == link,
|
||||||
|
|||||||
+43
-81
@@ -239,20 +239,24 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
8,
|
8,
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Padding(
|
child: PortalEntry(
|
||||||
padding: widget.showReactions
|
portal: Container(
|
||||||
? EdgeInsets.only(
|
transform: Matrix4.translationValues(-16, 2, 0),
|
||||||
top: widget.message.reactionCounts
|
child: _buildReactionIndicator(context),
|
||||||
?.isNotEmpty ==
|
constraints: BoxConstraints(maxWidth: 22 * 6.0),
|
||||||
true
|
),
|
||||||
? 12
|
portalAnchor: Alignment(-1.0, -1.0),
|
||||||
: 0,
|
childAnchor: Alignment(1, -1.0),
|
||||||
)
|
child: Padding(
|
||||||
: EdgeInsets.zero,
|
padding: widget.showReactions
|
||||||
child: PortalEntry(
|
? EdgeInsets.only(
|
||||||
portalAnchor: Alignment(-0.81, 0),
|
top: widget.message.reactionCounts
|
||||||
childAnchor: Alignment.topRight,
|
?.isNotEmpty ==
|
||||||
portal: _buildReactionIndicator(context),
|
true
|
||||||
|
? 18
|
||||||
|
: 0,
|
||||||
|
)
|
||||||
|
: EdgeInsets.zero,
|
||||||
child: (widget.message.isDeleted &&
|
child: (widget.message.isDeleted &&
|
||||||
widget.message.status !=
|
widget.message.status !=
|
||||||
MessageSendingStatus.FAILED_DELETE)
|
MessageSendingStatus.FAILED_DELETE)
|
||||||
@@ -378,75 +382,33 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReactionIndicator(BuildContext context) {
|
Widget _buildReactionIndicator(
|
||||||
final otherReactions = widget.message.latestReactions
|
BuildContext context,
|
||||||
?.where(
|
) {
|
||||||
(element) => element.user.id != StreamChat.of(context).user.id)
|
final ownId = StreamChat.of(context).user.id;
|
||||||
?.toList() ??
|
final reactionsMap = <String, Reaction>{};
|
||||||
[];
|
widget.message.latestReactions?.forEach((element) {
|
||||||
|
if (!reactionsMap.containsKey(element.type) || element.user.id == ownId) {
|
||||||
|
reactionsMap[element.type] = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final reactionsList = reactionsMap.values.toList()
|
||||||
|
..sort((a, b) => a.user.id == ownId ? 1 : -1);
|
||||||
|
|
||||||
var rowChildren = [
|
|
||||||
if (widget.message.ownReactions?.isNotEmpty == true) ...[
|
|
||||||
Transform.translate(
|
|
||||||
offset: Offset(
|
|
||||||
widget.reverse ? -6 : 0,
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
child: ReactionBubble(
|
|
||||||
key: ValueKey('${widget.message.id}.own'),
|
|
||||||
reverse: widget.reverse,
|
|
||||||
backgroundColor: widget.messageTheme.ownReactionsBackgroundColor,
|
|
||||||
borderColor: widget.messageTheme.ownReactionsBorderColor,
|
|
||||||
reactions: widget.message.ownReactions,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (otherReactions.isEmpty)
|
|
||||||
Container(
|
|
||||||
width: 18,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
if (otherReactions?.isNotEmpty == true) ...[
|
|
||||||
if (widget.message.ownReactions?.isEmpty == true)
|
|
||||||
Container(
|
|
||||||
width: 18,
|
|
||||||
),
|
|
||||||
Transform.translate(
|
|
||||||
offset: Offset(
|
|
||||||
widget.reverse ? 0 : -6,
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
child: ReactionBubble(
|
|
||||||
key: ValueKey('${widget.message.id}.other'),
|
|
||||||
reactions: otherReactions,
|
|
||||||
reverse: widget.reverse,
|
|
||||||
flipTail: true,
|
|
||||||
backgroundColor: widget.messageTheme.otherReactionsBackgroundColor,
|
|
||||||
borderColor: widget.messageTheme.otherReactionsBorderColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if (widget.reverse) {
|
|
||||||
rowChildren = rowChildren.reversed.toList();
|
|
||||||
}
|
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
child: (widget.showReactions &&
|
child: (widget.showReactions &&
|
||||||
(widget.message.reactionCounts?.isNotEmpty == true ||
|
(widget.message.reactionCounts?.isNotEmpty == true) &&
|
||||||
otherReactions.isNotEmpty) &&
|
|
||||||
!widget.message.isDeleted)
|
!widget.message.isDeleted)
|
||||||
? Container(
|
? GestureDetector(
|
||||||
child: GestureDetector(
|
onTap: () => _showMessageReactionsModalBottomSheet(context),
|
||||||
onTap: () => _showMessageReactionsModalBottomSheet(context),
|
child: ReactionBubble(
|
||||||
child: FractionallySizedBox(
|
key: ValueKey('${widget.message.id}.reactions'),
|
||||||
widthFactor: 0.5,
|
reverse: widget.reverse,
|
||||||
child: Row(
|
flipTail: widget.reverse,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
backgroundColor: widget.messageTheme.reactionsBackgroundColor,
|
||||||
mainAxisSize: MainAxisSize.min,
|
borderColor: widget.messageTheme.reactionsBorderColor,
|
||||||
children: rowChildren,
|
reactions: reactionsList,
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: SizedBox(),
|
: SizedBox(),
|
||||||
@@ -498,8 +460,8 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ContinuousRectangleBorder _getDefaultShape(BuildContext context) {
|
ShapeBorder _getDefaultShape(BuildContext context) {
|
||||||
return ContinuousRectangleBorder(
|
return RoundedRectangleBorder(
|
||||||
side: widget.attachmentBorderSide ??
|
side: widget.attachmentBorderSide ??
|
||||||
widget.borderSide ??
|
widget.borderSide ??
|
||||||
BorderSide(
|
BorderSide(
|
||||||
@@ -718,7 +680,7 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
onLongPress: () => onLongPress(context),
|
onLongPress: () => onLongPress(context),
|
||||||
child: Material(
|
child: Material(
|
||||||
shape: widget.shape ??
|
shape: widget.shape ??
|
||||||
ContinuousRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
side: widget.borderSide ??
|
side: widget.borderSide ??
|
||||||
BorderSide(
|
BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/reaction_icon.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
class ReactionBubble extends StatelessWidget {
|
class ReactionBubble extends StatelessWidget {
|
||||||
@@ -11,6 +13,7 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
@required this.backgroundColor,
|
@required this.backgroundColor,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
this.flipTail = false,
|
this.flipTail = false,
|
||||||
|
this.highlightOwnReactions = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final List<Reaction> reactions;
|
final List<Reaction> reactions;
|
||||||
@@ -18,67 +21,100 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
final bool flipTail;
|
final bool flipTail;
|
||||||
|
final bool highlightOwnReactions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final reactionIcons = StreamChatTheme.of(context).reactionIcons;
|
final reactionIcons = StreamChatTheme.of(context).reactionIcons;
|
||||||
|
final offset = reactions.length > 1 ? 16.0 : 2.0;
|
||||||
return Transform(
|
return Transform(
|
||||||
transform: Matrix4.rotationY(reverse ? pi : 0),
|
transform: Matrix4.rotationY(reverse ? pi : 0),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Column(
|
child: Stack(
|
||||||
crossAxisAlignment:
|
alignment: Alignment.center,
|
||||||
flipTail ? CrossAxisAlignment.start : CrossAxisAlignment.end,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Transform.translate(
|
||||||
padding: const EdgeInsets.all(4),
|
offset: Offset(reverse ? offset : -offset, 0),
|
||||||
decoration: BoxDecoration(
|
child: Container(
|
||||||
border: Border.all(
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
color: borderColor,
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: borderColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||||
),
|
),
|
||||||
color: backgroundColor,
|
child: LayoutBuilder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
builder: (context, constraints) {
|
||||||
),
|
return Flex(
|
||||||
child: Wrap(
|
direction: Axis.horizontal,
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
...reactions.map((reaction) {
|
children: [
|
||||||
final reactionIcon = reactionIcons.firstWhere(
|
if (constraints.maxWidth < double.infinity)
|
||||||
(r) => r.type == reaction.type,
|
...reactions
|
||||||
orElse: () => null,
|
.take((constraints.maxWidth) ~/ 22)
|
||||||
|
.map((reaction) {
|
||||||
|
return _buildReaction(
|
||||||
|
reactionIcons,
|
||||||
|
reaction,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
if (constraints.maxWidth == double.infinity)
|
||||||
|
...reactions.map((reaction) {
|
||||||
|
return _buildReaction(
|
||||||
|
reactionIcons,
|
||||||
|
reaction,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
if (reactionIcon == null) {
|
},
|
||||||
return Text(
|
),
|
||||||
'?',
|
|
||||||
style: TextStyle(
|
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Icon(
|
|
||||||
reactionIcon.iconData,
|
|
||||||
size: 16,
|
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildReactionsTail(context),
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: reverse ? null : 11,
|
||||||
|
right: !reverse ? null : 11,
|
||||||
|
child: _buildReactionsTail(context),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildReaction(
|
||||||
|
List<ReactionIcon> reactionIcons,
|
||||||
|
Reaction reaction,
|
||||||
|
BuildContext context,
|
||||||
|
) {
|
||||||
|
final reactionIcon = reactionIcons.firstWhere(
|
||||||
|
(r) => r.type == reaction.type,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 4.0,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
reactionIcon?.iconData ?? Icons.help_outline_rounded,
|
||||||
|
size: 16,
|
||||||
|
color: (!highlightOwnReactions ||
|
||||||
|
reaction.user.id == StreamChat.of(context).user.id)
|
||||||
|
? StreamChatTheme.of(context).accentColor
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildReactionsTail(BuildContext context) {
|
Widget _buildReactionsTail(BuildContext context) {
|
||||||
final tail = Transform.translate(
|
final tail = CustomPaint(
|
||||||
offset: Offset(reactions.length > 1 ? -9 : -9, 0),
|
painter: ReactionBubblePainter(
|
||||||
child: CustomPaint(
|
backgroundColor,
|
||||||
painter: ReactionBubblePainter(
|
borderColor,
|
||||||
backgroundColor,
|
|
||||||
borderColor,
|
|
||||||
reactions.length,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -97,12 +133,10 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
class ReactionBubblePainter extends CustomPainter {
|
class ReactionBubblePainter extends CustomPainter {
|
||||||
final Color color;
|
final Color color;
|
||||||
final Color borderColor;
|
final Color borderColor;
|
||||||
final int reactionsCount;
|
|
||||||
|
|
||||||
ReactionBubblePainter(
|
ReactionBubblePainter(
|
||||||
this.color,
|
this.color,
|
||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.reactionsCount,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -125,7 +159,7 @@ class ReactionBubblePainter extends CustomPainter {
|
|||||||
final path = Path();
|
final path = Path();
|
||||||
path.addOval(
|
path.addOval(
|
||||||
Rect.fromCircle(
|
Rect.fromCircle(
|
||||||
center: Offset(6, 2),
|
center: Offset(4, 3),
|
||||||
radius: 2,
|
radius: 2,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -139,7 +173,7 @@ class ReactionBubblePainter extends CustomPainter {
|
|||||||
|
|
||||||
final path = Path();
|
final path = Path();
|
||||||
path.addOval(Rect.fromCircle(
|
path.addOval(Rect.fromCircle(
|
||||||
center: Offset(6, 2),
|
center: Offset(4, 3),
|
||||||
radius: 2,
|
radius: 2,
|
||||||
));
|
));
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
@@ -151,13 +185,13 @@ class ReactionBubblePainter extends CustomPainter {
|
|||||||
..strokeWidth = 1
|
..strokeWidth = 1
|
||||||
..style = PaintingStyle.stroke;
|
..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
final dy = -2.2;
|
||||||
final startAngle = reactionsCount > 1 ? 1.08 : 1.16;
|
final startAngle = 1.1;
|
||||||
final sweepAngle = reactionsCount > 1 ? 0.95 : 1.1;
|
final sweepAngle = 1.2;
|
||||||
final path = Path();
|
final path = Path();
|
||||||
path.addArc(
|
path.addArc(
|
||||||
Rect.fromCircle(
|
Rect.fromCircle(
|
||||||
center: Offset(0, dy),
|
center: Offset(1, dy),
|
||||||
radius: 4,
|
radius: 4,
|
||||||
),
|
),
|
||||||
-pi * startAngle,
|
-pi * startAngle,
|
||||||
@@ -171,13 +205,13 @@ class ReactionBubblePainter extends CustomPainter {
|
|||||||
..color = color
|
..color = color
|
||||||
..strokeWidth = 1;
|
..strokeWidth = 1;
|
||||||
|
|
||||||
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
final dy = -2.2;
|
||||||
final startAngle = reactionsCount > 1 ? 1 : 1.16;
|
final startAngle = 1;
|
||||||
final sweepAngle = reactionsCount > 1 ? 1.2 : 1;
|
final sweepAngle = 1.3;
|
||||||
final path = Path();
|
final path = Path();
|
||||||
path.addArc(
|
path.addArc(
|
||||||
Rect.fromCircle(
|
Rect.fromCircle(
|
||||||
center: Offset(0, dy),
|
center: Offset(1, dy),
|
||||||
radius: 4,
|
radius: 4,
|
||||||
),
|
),
|
||||||
-pi * startAngle,
|
-pi * startAngle,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
fit: StackFit.passthrough,
|
fit: StackFit.passthrough,
|
||||||
children: [
|
children: [
|
||||||
Material(
|
Material(
|
||||||
color: messageTheme.ownReactionsBackgroundColor,
|
color: messageTheme.reactionsBackgroundColor,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
@@ -45,7 +45,7 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
reactionIcon.iconData,
|
reactionIcon.iconData,
|
||||||
color: ownReactionIndex != -1
|
color: ownReactionIndex != -1
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).accentColor
|
||||||
: Theme.of(context).iconTheme.color,
|
: Theme.of(context).iconTheme.color.withOpacity(.5),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (ownReactionIndex != -1) {
|
if (ownReactionIndex != -1) {
|
||||||
@@ -69,9 +69,8 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: ReactionBubblePainter(
|
painter: ReactionBubblePainter(
|
||||||
messageTheme.ownReactionsBackgroundColor,
|
messageTheme.reactionsBackgroundColor,
|
||||||
messageTheme.ownReactionsBorderColor,
|
messageTheme.reactionsBorderColor,
|
||||||
2,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+15
-16
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app_badger/flutter_app_badger.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
@@ -129,14 +130,9 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints,
|
constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints,
|
||||||
borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius,
|
borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius,
|
||||||
),
|
),
|
||||||
otherReactionsBorderColor:
|
reactionsBorderColor: themeData?.ownMessageTheme?.reactionsBorderColor,
|
||||||
themeData?.ownMessageTheme?.otherReactionsBorderColor,
|
reactionsBackgroundColor:
|
||||||
otherReactionsBackgroundColor:
|
themeData?.ownMessageTheme?.reactionsBackgroundColor,
|
||||||
themeData?.ownMessageTheme?.otherReactionsBackgroundColor,
|
|
||||||
ownReactionsBackgroundColor:
|
|
||||||
themeData?.ownMessageTheme?.ownReactionsBackgroundColor,
|
|
||||||
ownReactionsBorderColor:
|
|
||||||
themeData?.ownMessageTheme?.ownReactionsBorderColor,
|
|
||||||
),
|
),
|
||||||
otherMessageTheme: defaultTheme.otherMessageTheme.copyWith(
|
otherMessageTheme: defaultTheme.otherMessageTheme.copyWith(
|
||||||
replies: themeData?.otherMessageTheme?.replies,
|
replies: themeData?.otherMessageTheme?.replies,
|
||||||
@@ -150,14 +146,10 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints,
|
constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints,
|
||||||
borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius,
|
borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius,
|
||||||
),
|
),
|
||||||
otherReactionsBorderColor:
|
reactionsBorderColor:
|
||||||
themeData?.otherMessageTheme?.otherReactionsBorderColor,
|
themeData?.otherMessageTheme?.reactionsBorderColor,
|
||||||
otherReactionsBackgroundColor:
|
reactionsBackgroundColor:
|
||||||
themeData?.otherMessageTheme?.otherReactionsBackgroundColor,
|
themeData?.otherMessageTheme?.reactionsBackgroundColor,
|
||||||
ownReactionsBackgroundColor:
|
|
||||||
themeData?.otherMessageTheme?.ownReactionsBackgroundColor,
|
|
||||||
ownReactionsBorderColor:
|
|
||||||
themeData?.otherMessageTheme?.ownReactionsBorderColor,
|
|
||||||
),
|
),
|
||||||
accentColor: themeData?.accentColor,
|
accentColor: themeData?.accentColor,
|
||||||
secondaryColor: themeData?.secondaryColor,
|
secondaryColor: themeData?.secondaryColor,
|
||||||
@@ -186,6 +178,13 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
client.state?.totalUnreadCountStream?.listen((count) {
|
||||||
|
if (count > 0) {
|
||||||
|
FlutterAppBadger.updateBadgeCount(count);
|
||||||
|
} else {
|
||||||
|
FlutterAppBadger.removeBadge();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSubscription _newMessageSubscription;
|
StreamSubscription _newMessageSubscription;
|
||||||
|
|||||||
@@ -220,8 +220,8 @@ class StreamChatThemeData {
|
|||||||
return StreamChatThemeData(
|
return StreamChatThemeData(
|
||||||
accentColor: accentColor,
|
accentColor: accentColor,
|
||||||
primaryColor: isDark ? Colors.black : Colors.white,
|
primaryColor: isDark ? Colors.black : Colors.white,
|
||||||
primaryIconTheme:
|
primaryIconTheme: IconThemeData(
|
||||||
IconThemeData(color: isDark ? Colors.white : Colors.black),
|
color: isDark ? Colors.white : Colors.black.withOpacity(.5)),
|
||||||
defaultChannelImage: (context, channel) => SizedBox(),
|
defaultChannelImage: (context, channel) => SizedBox(),
|
||||||
backgroundColor: isDark ? Colors.black : Colors.white,
|
backgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
defaultUserImage: (context, user) => Center(
|
defaultUserImage: (context, user) => Center(
|
||||||
@@ -287,7 +287,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
ownMessageTheme: MessageTheme(
|
ownMessageTheme: MessageTheme(
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 14.5,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
@@ -302,12 +302,8 @@ class StreamChatThemeData {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
ownReactionsBackgroundColor:
|
reactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
ownReactionsBorderColor: isDark ? Colors.black : Colors.white,
|
|
||||||
otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
|
||||||
otherReactionsBorderColor:
|
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -320,14 +316,11 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageTheme(
|
otherMessageTheme: MessageTheme(
|
||||||
ownReactionsBackgroundColor:
|
reactionsBackgroundColor:
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
|
||||||
ownReactionsBorderColor: isDark ? Colors.black : Colors.white,
|
|
||||||
otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
|
||||||
otherReactionsBorderColor:
|
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
|
reactionsBorderColor: isDark ? Colors.black : Colors.white,
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 14.5,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
@@ -457,10 +450,8 @@ class MessageTheme {
|
|||||||
final TextStyle createdAt;
|
final TextStyle createdAt;
|
||||||
final TextStyle replies;
|
final TextStyle replies;
|
||||||
final Color messageBackgroundColor;
|
final Color messageBackgroundColor;
|
||||||
final Color ownReactionsBackgroundColor;
|
final Color reactionsBackgroundColor;
|
||||||
final Color ownReactionsBorderColor;
|
final Color reactionsBorderColor;
|
||||||
final Color otherReactionsBackgroundColor;
|
|
||||||
final Color otherReactionsBorderColor;
|
|
||||||
final AvatarTheme avatarTheme;
|
final AvatarTheme avatarTheme;
|
||||||
|
|
||||||
const MessageTheme({
|
const MessageTheme({
|
||||||
@@ -469,10 +460,8 @@ class MessageTheme {
|
|||||||
this.messageAuthor,
|
this.messageAuthor,
|
||||||
this.messageLinks,
|
this.messageLinks,
|
||||||
this.messageBackgroundColor,
|
this.messageBackgroundColor,
|
||||||
this.ownReactionsBackgroundColor,
|
this.reactionsBackgroundColor,
|
||||||
this.ownReactionsBorderColor,
|
this.reactionsBorderColor,
|
||||||
this.otherReactionsBackgroundColor,
|
|
||||||
this.otherReactionsBorderColor,
|
|
||||||
this.avatarTheme,
|
this.avatarTheme,
|
||||||
this.createdAt,
|
this.createdAt,
|
||||||
});
|
});
|
||||||
@@ -485,10 +474,8 @@ class MessageTheme {
|
|||||||
TextStyle replies,
|
TextStyle replies,
|
||||||
Color messageBackgroundColor,
|
Color messageBackgroundColor,
|
||||||
AvatarTheme avatarTheme,
|
AvatarTheme avatarTheme,
|
||||||
Color ownReactionsBackgroundColor,
|
Color reactionsBackgroundColor,
|
||||||
Color ownReactionsBorderColor,
|
Color reactionsBorderColor,
|
||||||
Color otherReactionsBackgroundColor,
|
|
||||||
Color otherReactionsBorderColor,
|
|
||||||
}) =>
|
}) =>
|
||||||
MessageTheme(
|
MessageTheme(
|
||||||
messageText: messageText ?? this.messageText,
|
messageText: messageText ?? this.messageText,
|
||||||
@@ -499,14 +486,9 @@ class MessageTheme {
|
|||||||
messageBackgroundColor ?? this.messageBackgroundColor,
|
messageBackgroundColor ?? this.messageBackgroundColor,
|
||||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
replies: replies ?? this.replies,
|
replies: replies ?? this.replies,
|
||||||
ownReactionsBackgroundColor:
|
reactionsBackgroundColor:
|
||||||
ownReactionsBackgroundColor ?? this.ownReactionsBackgroundColor,
|
reactionsBackgroundColor ?? this.reactionsBackgroundColor,
|
||||||
ownReactionsBorderColor:
|
reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor,
|
||||||
ownReactionsBorderColor ?? this.ownReactionsBorderColor,
|
|
||||||
otherReactionsBackgroundColor:
|
|
||||||
otherReactionsBackgroundColor ?? this.otherReactionsBackgroundColor,
|
|
||||||
otherReactionsBorderColor:
|
|
||||||
otherReactionsBorderColor ?? this.otherReactionsBorderColor,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -11,16 +11,17 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_app_badger: ^1.1.2
|
||||||
photo_view: ^0.10.1
|
photo_view: ^0.10.1
|
||||||
rxdart: ^0.24.1
|
rxdart: ^0.24.1
|
||||||
jiffy: ^3.0.1
|
jiffy: ^3.0.1
|
||||||
flutter_portal: ^0.3.0
|
flutter_portal: ^0.3.0
|
||||||
cached_network_image: ^2.2.0+1
|
cached_network_image: ^2.2.0+1
|
||||||
flutter_markdown: ^0.4.2
|
flutter_markdown: ^0.5.0
|
||||||
url_launcher: ^5.4.11
|
url_launcher: ^5.4.11
|
||||||
video_player: ^0.10.11+1
|
video_player: ^0.10.12+5
|
||||||
chewie: ^0.9.10
|
chewie: ^0.9.10
|
||||||
file_picker: ^2.0.0
|
file_picker: ^2.0.8+1
|
||||||
image_picker: ^0.6.7+2
|
image_picker: ^0.6.7+2
|
||||||
flutter_keyboard_visibility: ^3.2.1
|
flutter_keyboard_visibility: ^3.2.1
|
||||||
stream_chat: ^0.2.10
|
stream_chat: ^0.2.10
|
||||||
|
|||||||
@@ -10,13 +10,21 @@ void main() {
|
|||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show one thumbs from the picker',
|
'it should show one thumbs from the picker',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
final themeData = ThemeData();
|
final themeData = ThemeData();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: themeData,
|
theme: themeData,
|
||||||
home: StreamChatTheme(
|
home: StreamChat(
|
||||||
data: streamTheme,
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
child: MessageReactionsModal(
|
child: MessageReactionsModal(
|
||||||
message: Message(
|
message: Message(
|
||||||
id: 'test',
|
id: 'test',
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show no reactions',
|
'it should show no reactions',
|
||||||
@@ -29,17 +32,25 @@ void main() {
|
|||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show a thumb up',
|
'it should show a thumb up',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
final themeData = ThemeData();
|
final themeData = ThemeData();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: themeData,
|
theme: themeData,
|
||||||
home: StreamChatTheme(
|
home: StreamChat(
|
||||||
data: StreamChatThemeData.getDefaultTheme(themeData),
|
client: client,
|
||||||
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
child: Container(
|
child: Container(
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
reactions: [
|
reactions: [
|
||||||
Reaction(
|
Reaction(
|
||||||
type: 'thumbs_up',
|
type: 'thumbs_up',
|
||||||
|
user: User(id: 'test'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
borderColor: Colors.black,
|
borderColor: Colors.black,
|
||||||
@@ -56,20 +67,29 @@ void main() {
|
|||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show two reactions',
|
'it should show two reactions',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
final themeData = ThemeData();
|
final themeData = ThemeData();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: themeData,
|
theme: themeData,
|
||||||
home: StreamChatTheme(
|
home: StreamChat(
|
||||||
data: StreamChatThemeData.getDefaultTheme(themeData),
|
client: client,
|
||||||
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
child: Container(
|
child: Container(
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
reactions: [
|
reactions: [
|
||||||
Reaction(
|
Reaction(
|
||||||
type: 'thumbs_up',
|
type: 'thumbs_up',
|
||||||
|
user: User(id: 'test'),
|
||||||
),
|
),
|
||||||
Reaction(
|
Reaction(
|
||||||
type: 'love',
|
type: 'love',
|
||||||
|
user: User(id: 'test'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
borderColor: Colors.black,
|
borderColor: Colors.black,
|
||||||
|
|||||||
Reference in New Issue
Block a user