imessage fix (#6)

* first draft : static views wip

* refactor to ChatMessage and ChatMessageHeader

* add pedantic

* fix lints

* remove hardcoded message

* appBar title : iMessage

* format date

* cupertino style and model view

* fix display of message based on isReceived or sent

* SendMessageInput

* refactor to MessagesPage

* MissingPluginException

* use builtins instead of custom stream builders

* handle isReceived

* delete channel header

* fix layout issues in ChannelPreview

* fix formatDate

* sticky message input

* usage of builtin MessageListCore

* remove unused imports and a todo

* rename channelsStates to channels

* replace file imports /w package:imessage/filename

* remove size required ChannelNameText

* lint and format

* sendMessage

* transition animation

* stream_chat_flutter_core instead

* format Date differently if same week

* add padding to bubble

* remove iMessage text from header

* reverse message order

* if same day don't display date

* padding chat bubble right

* remove unused extension

* constraint message width

* group messages By dates

* unused import

* fix bug input + layout+ preview onTap

* change updatedAt to createdAt

* add filter on channel

* handle refresh

* handle pagination with core LazyLoadScrollView

* preview simple medias

* upload bug

* fix attachment

* visual changes to message input

* remove size

* clean up

* wait 5 sec before displaying image(hack)

* fix a couple of things

* fix padding in channel preview

* fix upload + debugShowCheckedModeBanner false

* fix overflow and refactor to Divider

* fix android build

* add imessage clone hero image

* update README

Co-authored-by: Sacha Arbonel <sacha.arbonel@hotmail.fr>
This commit is contained in:
Salvatore Giordano
2021-02-26 18:06:54 +01:00
committed by GitHub
parent 6feccd57dd
commit f861eb4584
21 changed files with 344 additions and 279 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+46 -9
View File
@@ -1,16 +1,53 @@
# imessage
# iMessage Clone
A new Flutter project.
![](https://raw.githubusercontent.com/GetStream/flutter-samples/master/images/imessage_clone_hero_v1.png)
iMessage Clone is a sample app implemented using Stream Chat and Flutter. It is a fully fledged messaging app built using core packages.
## Getting Started
This project is a starting point for a Flutter application.
Before running this project please ensure Flutter is installed and configured on your machine. If you're new to Flutter, please checkout the [official guide](https://flutter.dev/docs/get-started/install) with installation instructions for your OS.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
This project is only configured to support the following platforms:
- Android
- iOS
Web and Desktop are not supported at this time.
After installing Flutter and the necessary toolchain for your device (Android or iOS), connect your device or open your emulator before running the following:
**Clone the repo**
```bash
git clone https://github.com/GetStream/flutter-samples
```
**Open the app folder**
```bash
cd flutter-samples/imessage
```
**Install package dependencies:**
```bash
flutter packages get
```
**Open or create an emulator**
```bash
# To run an emulator, run 'flutter emulators --launch <emulator id>'.
# To create a new emulator, run 'flutter emulators --create [--name xyz]'.
# You can find more information on managing emulators at the links below:
# [https://developer.android.com/studio/run/managing-avds](https://developer.android.com/studio/run/managing-avds)[https://developer.android.com/studio/command-line/avdmanager](https://developer.android.com/studio/command-line/avdmanager)
```
**Run the project on your device or emulator:**
```bash
flutter run
```
+1 -1
View File
@@ -35,7 +35,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.imessage"
minSdkVersion 16
minSdkVersion 21
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
+1
View File
@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true
+2 -2
View File
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
@@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>10.0</string>
</dict>
</plist>
-1
View File
@@ -1,3 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
-1
View File
@@ -1,3 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+58 -75
View File
@@ -9,11 +9,11 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
54127ED34F2B67975767881F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F124A271054C4FEB7BA298EA /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
AD80798B75BEF39A28B8324C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0EA12FA64E96796BC730E03 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -30,14 +30,15 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
10AA3A20A8E8F51016843518 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1DFBF673D502906C56E28E7F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
212173E324AE0FED45F2866A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7851D9CF8A0104A48AF22BF4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
87BC4F0CB1D55BC3C77185AD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -45,8 +46,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F124A271054C4FEB7BA298EA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F6E360FB0F19A8EE63C4281A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
D0EA12FA64E96796BC730E03 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -54,27 +54,27 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
54127ED34F2B67975767881F /* Pods_Runner.framework in Frameworks */,
AD80798B75BEF39A28B8324C /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
053DC9E602F5F5F21DC144A5 /* Frameworks */ = {
3F98BA59D9BB09C5816FF126 /* Frameworks */ = {
isa = PBXGroup;
children = (
F124A271054C4FEB7BA298EA /* Pods_Runner.framework */,
D0EA12FA64E96796BC730E03 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
15FB9768D11A361EAB687B81 /* Pods */ = {
7231B8C27F5ACE1DDE056446 /* Pods */ = {
isa = PBXGroup;
children = (
1DFBF673D502906C56E28E7F /* Pods-Runner.debug.xcconfig */,
7851D9CF8A0104A48AF22BF4 /* Pods-Runner.release.xcconfig */,
F6E360FB0F19A8EE63C4281A /* Pods-Runner.profile.xcconfig */,
87BC4F0CB1D55BC3C77185AD /* Pods-Runner.debug.xcconfig */,
10AA3A20A8E8F51016843518 /* Pods-Runner.release.xcconfig */,
212173E324AE0FED45F2866A /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
@@ -97,8 +97,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
15FB9768D11A361EAB687B81 /* Pods */,
053DC9E602F5F5F21DC144A5 /* Frameworks */,
7231B8C27F5ACE1DDE056446 /* Pods */,
3F98BA59D9BB09C5816FF126 /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -132,14 +132,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
F8BE585E4B71465AB994DDE3 /* [CP] Check Pods Manifest.lock */,
CAA82304056351F698F2FE92 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
FF3AE7DF11C51CD94F69B7CD /* [CP] Embed Pods Frameworks */,
5C9569EFDB9DD32B2BAFBEBB /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -212,6 +212,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
5C9569EFDB9DD32B2BAFBEBB /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -226,7 +243,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
F8BE585E4B71465AB994DDE3 /* [CP] Check Pods Manifest.lock */ = {
CAA82304056351F698F2FE92 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -248,64 +265,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
FF3AE7DF11C51CD94F69B7CD /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
"${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework",
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
"${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework",
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
"${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework",
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
"${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
"${BUILT_PRODUCTS_DIR}/video_compress/video_compress.framework",
"${BUILT_PRODUCTS_DIR}/video_player/video_player.framework",
"${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework",
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.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}/image_gallery_saver.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_compress.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -398,8 +357,16 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.imessage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -522,8 +489,16 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.imessage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -541,8 +516,16 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.imessage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
+11 -8
View File
@@ -13,11 +13,13 @@ class ChannelListView extends StatelessWidget {
channels.removeWhere((channel) => channel.lastMessageAt == null);
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
//TODO: separators
return Column(
children: [
ChannelPreview(
(
BuildContext context,
int index,
) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: ChannelPreview(
channel: channels[index],
onTap: () {
Navigator.push(
@@ -39,9 +41,10 @@ class ChannelListView extends StatelessWidget {
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.horizontal,
),
));
})
],
),
);
},
),
);
},
childCount: channels.length,
+8 -4
View File
@@ -2,8 +2,11 @@ import 'package:flutter/cupertino.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel;
class ChannelNameText extends StatelessWidget {
const ChannelNameText({Key key, @required this.channel, this.size = 12})
: super(key: key);
const ChannelNameText({
Key key,
@required this.channel,
this.size = 17,
}) : super(key: key);
final Channel channel;
final double size;
@@ -11,11 +14,12 @@ class ChannelNameText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
channel.extraData['name'] as String ?? channel.config.name,
channel.extraData['name'] as String ?? 'No name',
style: TextStyle(
fontSize: size,
fontWeight: FontWeight.bold,
color: CupertinoColors.black),
color: CupertinoColors.black,
),
);
}
}
+44 -22
View File
@@ -9,6 +9,7 @@ import 'utils.dart';
class ChannelPreview extends StatelessWidget {
final VoidCallback onTap;
final Channel channel;
const ChannelPreview({
Key key,
@required this.onTap,
@@ -24,9 +25,9 @@ class ChannelPreview extends StatelessWidget {
? lastMessage?.attachments //TODO: ugly
?.map((e) {
if (e.type == 'image') {
return '📷';
return '📷 ';
} else if (e.type == 'video') {
return '🎬';
return '🎬 ';
}
return null;
})
@@ -35,41 +36,59 @@ class ChannelPreview extends StatelessWidget {
: '';
return GestureDetector(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
behavior: HitTestBehavior.opaque,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: CupertinoColors.white),
child: Row(
children: [
ChannelImage(channel: channel, size: 50),
Expanded(
constraints: BoxConstraints.tightFor(
height: 90,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
child: ChannelImage(
channel: channel,
size: 50,
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ChannelNameText(
channel: channel,
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: [
Text(
isSameWeek(channel.lastMessageAt)
? formatDateSameWeek(channel.lastMessageAt)
: formatDate(channel.lastMessageAt),
style: TextStyle(
fontWeight: FontWeight.bold,
color: CupertinoColors.systemGrey),
fontSize: 15,
color: CupertinoColors.systemGrey,
),
),
Icon(
CupertinoIcons.right_chevron,
color: CupertinoColors.systemGrey3,
),
],
),
)
],
@@ -77,16 +96,19 @@ class ChannelPreview extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'$prefix ${lastMessage?.text ?? ''}',
'$prefix${lastMessage?.text ?? ''}',
style: TextStyle(
fontWeight: FontWeight.normal,
color: CupertinoColors.systemGrey),
color: CupertinoColors.systemGrey,
fontSize: 16,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Divider(),
],
),
),
)
],
),
+13 -12
View File
@@ -43,6 +43,7 @@ class IMessage extends StatelessWidget {
initializeDateFormatting('en_US', null);
return CupertinoApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: CupertinoThemeData(brightness: Brightness.light),
home: StreamChatCore(client: client, child: ChatLoader()),
);
@@ -50,31 +51,26 @@ class IMessage extends StatelessWidget {
}
class ChatLoader extends StatelessWidget {
const ChatLoader({
ChatLoader({
Key key,
}) : super(key: key);
final channelListController = ChannelListController();
@override
Widget build(BuildContext context) {
final user = StreamChatCore.of(context).user;
var channelListController = ChannelListController();
return CupertinoPageScaffold(
child: ChannelsBloc(
child: ChannelListCore(
channelListController: channelListController,
filter: {
r'$and': [
{
'members': {
r'$in': [user.id],
}
},
{
'type': {
r'$eq': 'messaging',
}
}
]
},
},
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
@@ -108,13 +104,18 @@ class ChatLoader extends StatelessWidget {
onEndOfPage: () async {
channelListController.paginateData();
},
child: CustomScrollView(slivers: [
child: CustomScrollView(
slivers: [
CupertinoSliverRefreshControl(onRefresh: () async {
channelListController.loadData();
}),
ChannelPageAppBar(),
ChannelListView(channels: channels)
]),
SliverPadding(
sliver: ChannelListView(channels: channels),
padding: const EdgeInsets.only(top: 16),
)
],
),
))));
}
}
+4 -2
View File
@@ -9,8 +9,10 @@ class MessageHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
final receivedAt = DateTime.parse(rawTimeStamp);
var textStyle = TextStyle(
fontWeight: FontWeight.bold, color: CupertinoColors.systemGrey);
final textStyle = TextStyle(
color: CupertinoColors.systemGrey,
fontSize: 14,
);
return isSameWeek(receivedAt)
? Text(
formatDateSameWeek(receivedAt),
+11 -7
View File
@@ -12,21 +12,21 @@ class MessageListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final entries = groupBy(messages.reversed,
final entries = groupBy(messages,
(Message message) => message.createdAt.toString().substring(0, 10))
.entries
.toList();
return Stack(
return Column(
children: [
SizedBox(
Expanded(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.9,
child: Align(
alignment: FractionalOffset.topCenter,
child: ListView.builder(
shrinkWrap: true,
reverse: true,
itemCount: entries.length,
itemBuilder: (context, index) {
return Column(
children: [
Padding(
@@ -35,7 +35,8 @@ class MessageListView extends StatelessWidget {
child: MessageHeader(
rawTimeStamp: entries[index].key), //date
),
...entries[index].value //messages
...entries[index]
.value //messages
.map((message) {
return MessageWidget(
alignment: isReceived(message, context)
@@ -49,11 +50,14 @@ class MessageListView extends StatelessWidget {
: CupertinoColors.white,
message: message,
);
}).toList()
})
.toList()
.reversed,
],
);
}),
)),
),
MessageInput()
],
);
+8 -2
View File
@@ -21,8 +21,14 @@ class MessagePage extends StatelessWidget {
navigationBar: CupertinoNavigationBar(
middle: Column(
children: [
ChannelImage(size: 25, channel: streamChannel.channel),
ChannelNameText(channel: streamChannel.channel)
ChannelImage(
size: 25,
channel: streamChannel.channel,
),
ChannelNameText(
size: 16,
channel: streamChannel.channel,
),
],
),
), //ChannelHeader
+13 -16
View File
@@ -1,7 +1,8 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:imessage/cutom_painter.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Message, AttachmentUploadStateBuilder;
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
show Message, AttachmentUploadStateBuilder;
class MessageWidget extends StatelessWidget {
final Alignment alignment;
@@ -19,7 +20,7 @@ class MessageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (message.attachments.isNotEmpty &&
if (message.attachments?.isNotEmpty == true &&
message.attachments.first.type == "image") {
return MessageImage(
color: color, message: message, messageColor: messageColor);
@@ -58,21 +59,17 @@ class MessageImage extends StatelessWidget {
color: color,
child: Column(
children: [
FutureBuilder<String>( //hack: //AttachmentUploadStateBuilder once https://github.com/GetStream/stream-chat-flutter/pull/276 is merged
future: Future.delayed(
const Duration(seconds: 5),
() =>
message.attachments.first.thumbUrl ??
message.attachments.first.imageUrl ??
message.attachments.first.assetUrl),
builder: (context, snapshot) {
return snapshot.hasData
? CachedNetworkImage(
imageUrl: snapshot.data,
if (message.attachments.first.file != null)
Image.memory(
message.attachments.first.file.bytes,
fit: BoxFit.cover,
)
: CupertinoActivityIndicator();
}),
else
CachedNetworkImage(
imageUrl: message.attachments.first.thumbUrl ??
message.attachments.first.imageUrl ??
message.attachments.first.assetUrl,
),
if (message.attachments.first?.title != null)
Padding(
padding: const EdgeInsets.all(8.0),
+29 -4
View File
@@ -8,13 +8,17 @@ String formatDate(DateTime date) {
}
String formatDateSameWeek(DateTime date) {
final dateFormat = DateFormat('EEEE, hh:mm a');
DateFormat dateFormat;
if (date.day == DateTime.now().day) {
dateFormat = DateFormat('hh:mm a');
} else {
dateFormat = DateFormat('EEEE, hh:mm a');
}
return dateFormat.format(date);
}
String formatDateMessage(DateTime date) {
final dateFormat =
DateFormat('EEE. MMM. d ' 'yy' ' hh:mm a');
final dateFormat = DateFormat('EEE. MMM. d ' 'yy' ' hh:mm a');
return dateFormat.format(date);
}
@@ -35,7 +39,8 @@ class CupertinoCircleAvatar extends StatelessWidget {
height: size,
width: size,
fit: BoxFit.cover,
errorWidget: (context, url, error) { //TODO: this crash the app when getting 404 and in debug mode, see :https://github.com/Baseflow/flutter_cached_network_image/issues/504
errorWidget: (context, url, error) {
//TODO: this crash the app when getting 404 and in debug mode, see :https://github.com/Baseflow/flutter_cached_network_image/issues/504
return CachedNetworkImage(
imageUrl:
"https://4.bp.blogspot.com/-Jx21kNqFSTU/UXemtqPhZCI/AAAAAAAAh74/BMGSzpU6F48/s1600/funny-cat-pictures-047-001.jpg");
@@ -43,3 +48,23 @@ class CupertinoCircleAvatar extends StatelessWidget {
);
}
}
class Divider extends StatelessWidget {
const Divider({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: Align(
child: Container(
height: 1,
color: CupertinoColors.systemGrey5,
),
alignment: Alignment.bottomCenter,
),
);
}
}
+6 -1
View File
@@ -24,7 +24,12 @@ dependencies:
flutter:
sdk: flutter
intl: ^0.16.1
stream_chat_flutter: ^1.2.0-beta
#stream_chat_flutter: ^1.2.0-beta
stream_chat_flutter:
git:
url: git://github.com/GetStream/stream-chat-flutter.git
path: packages/stream_chat_flutter
ref: develop
animations: ^1.0.0+5
collection: ^1.14.13
cached_network_image: ^2.0.0-rc