Skip to content

Commit

Permalink
feat(mess): editable, location, renderMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
vokhuyetOz committed May 10, 2024
1 parent e0cae8a commit 5608b90
Show file tree
Hide file tree
Showing 34 changed files with 1,161 additions and 446 deletions.
177 changes: 161 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
# react-native-messy

chat ui

Chat ui for React Native
<p>
<img src="preview/demo_1.png" width="200px">
<img src="preview/demo_2.png" width="200px">
</p>

## Dependency

- [discord/bottom-sheet](discord/react-native-bottom-sheet#discord-fork-4.6.1-rngh-v2)
- [react-native-keyboard-controller](https://kirillzyusko.github.io/react-native-keyboard-controller/)
- [react-native-image-picker](https://github.com/react-native-image-picker/react-native-image-picker)
- [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler#readme)
- [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated#readme)
- [react-native-tab-view](https://reactnavigation.org/docs/tab-view/)
- [react-native-video](https://github.com/TheWidlarzGroup/react-native-video)
- [@shopify/flash-list](https://shopify.github.io/flash-list/)

## Installation

Expand All @@ -17,32 +31,163 @@ yarn add @vokhuyet/react-native-messy

## Usage

```js
```ts
import { Messy } from '@vokhuyet/react-native-messy';

// ...
const [mess, setMess] = useState([]);
const [list, setList] = useState([]);

<Messy
messages={list}
loading={isLoading}
BaseModule={{
Cache: CacheDimension,
Image: ChatListImage,
Text: AppText,
}}
renderLoading={renderLoading}
renderMessageSystem={ChatListMessageSystem}
listProps={{
...FlatlistProps
onEndReached,
ListHeaderComponent: ChatListHeader,
}}
messageProps={{
hideOwnerAvatar: true,
hidePartnerAvatar: false,
onPress: onPressMessage,
onLongPress: onLongPressMessage,
}}
messages={mess}
user={{ id: 2 }}
user={{id: account?.user?.id}}
footerProps={{
onSend: async (message) => {
mess.unshift(message);
setMess([...mess]);
// upload image, sent text, emit event...
setTimeout(() => {
mess[0].status = 'sent';
setMess([...mess]);
}, 2000);
},
onSend,
ExtraLeft: <ChatListExtraLeft />,
ExtraActionLeft: <ChatListExtraActionLeft />,
}}
/>
```

## Object Type

### TMessyMessageLocation

```typescript
name: string;
image: ImageProps['source'];
latitude: string;
longitude: string;
```

### TMessyMessage

```ts
id?: string | number | null;
text?: string;
image?: ImageSourcePropType;
video?: { uri: string };
audio?: {uri: string}; // not implemented, you can implement by yourself
location?: TMessyMessageLocation;
user?: TUser;
type?: 'system' | 'message';
createdTime?: Date | number | string;
status?: 'sending' | 'sent' | 'seen';
seenBy?: TUser[];
local?: Asset;
clientId?: string; // used for display message in List before receiving response from Server
category?: string; // used for display multiple type of system message
```

### TColor

```ts
background: string;
primary: string;
accent: string;
placeholder: string;
shadow: string;
success: string;
message_left: {
background: string;
text: string;
link: string;
email: string;
phone: string;
audio: string;
};
message_right: {
background: string;
text: string;
link: string;
email: string;
phone: string;
audio: string;
};
input: {
text: string; //text color in TextInput
};
```

### TUser

```ts
id: string | number | null | undefined;
userName?: string | null;
avatar?: ImageSource;
```

### TMessyFooterProps

```ts
onSend?: (message?: TMessyMessage) => Promise<void> | void;
inputProps?: TextInputProps;
ExtraLeft?: React.ReactNode;
ExtraActionLeft?: React.ReactNode;
renderFooter?: FC<TMessyFooterProps>;
```

### TMessageProps

```ts
hideOwnerAvatar: boolean;
hidePartnerAvatar: boolean;
onPress?: (message: TMessyMessageProps) => Promise<void> | void;
onLongPress?: (message: TMessyMessageProps) => Promise<void> | void;
```

### TBaseModule

```ts
Image?: FC<ImageProps>;
Text?: FC<TextProps>;
Video?: FC;
Cache: {
get: (key: string) => any;
set: (key: string, value: any) => void;
};
```

## Props

- ```loading```(boolean): loading status
- **```messages```**([TMessyMessage[]](#tmessymessage)): list of messages
- ```user```([TUser](#tuser)): sender information;
- ```theme```: ([TColor](#tcolor)): custom theme for message;
- ```footerProps```([TMessyFooterProps](#tmessyfooterprops)): Custom props for Element below list messages;
- ```listProps```(TListProps): custom flatlist props;
- ```messageProps```([TMessageProps](#tmessageprops)): ;
- ```parsedShape```([ParseShape[]](https://github.com/taskrabbit/react-native-parsed-text)): Custom parse patterns for react-native-parsed-text ;
- ```showDateTime```(boolean): show created time of message;
- ```renderLoading```(FC<{}>): component when loading list message;
- ```renderMessageSystem```(FC<{ data?: TMessyMessage }>): custom system message;
- ```renderMessage```((data: TMessyMessageProps) => JSX.Element): custom whole message item view;
- ```renderAvatar```FC<{ user?: TUser }>: custom ;
- ```renderMessageText```((data: TMessyMessageProps) => JSX.Element): custom text message;
- ```renderMessageAudio```(data: TMessyMessageProps) => JSX.Element;
- ```renderMessageImage```(data: TMessyMessageProps) => JSX.Element;
- ```renderMessageVideo```(data: TMessyMessageProps) => JSX.Element;
- ```renderMessageDateTime```((data: TMessyMessage) => JSX.Element): custom datetime value in message item
- ```renderMessageLocation```: (data: TMessyMessageProps) => JSX.Element;
- ```BaseModule```([TBaseModule](#tbasemodule));

## Contributing

See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
Expand Down
38 changes: 30 additions & 8 deletions example/ios/MessyExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* MessyExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* MessyExampleTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-MessyExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-MessyExample.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
7699B88040F8A987B510C191 /* libPods-MessyExample-MessyExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-MessyExample-MessyExampleTests.a */; };
528AE9B4930F0DE7629654FA /* Pods_MessyExample_MessyExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5AC67C5C7E909C1F9F374F97 /* Pods_MessyExample_MessyExampleTests.framework */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
F17EB013D0B7C820D2EE5086 /* Pods_MessyExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 234C33D5E1A5F2A618956A88 /* Pods_MessyExample.framework */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -36,11 +36,11 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = MessyExample/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = MessyExample/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = MessyExample/main.m; sourceTree = "<group>"; };
19F6CBCC0A4E27FBF8BF4A61 /* libPods-MessyExample-MessyExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MessyExample-MessyExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
234C33D5E1A5F2A618956A88 /* Pods_MessyExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MessyExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B4392A12AC88292D35C810B /* Pods-MessyExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MessyExample.debug.xcconfig"; path = "Target Support Files/Pods-MessyExample/Pods-MessyExample.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-MessyExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MessyExample.release.xcconfig"; path = "Target Support Files/Pods-MessyExample/Pods-MessyExample.release.xcconfig"; sourceTree = "<group>"; };
5AC67C5C7E909C1F9F374F97 /* Pods_MessyExample_MessyExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MessyExample_MessyExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5B7EB9410499542E8C5724F5 /* Pods-MessyExample-MessyExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MessyExample-MessyExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-MessyExample-MessyExampleTests/Pods-MessyExample-MessyExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-MessyExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MessyExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = MessyExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* Pods-MessyExample-MessyExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MessyExample-MessyExampleTests.release.xcconfig"; path = "Target Support Files/Pods-MessyExample-MessyExampleTests/Pods-MessyExample-MessyExampleTests.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
Expand All @@ -51,15 +51,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7699B88040F8A987B510C191 /* libPods-MessyExample-MessyExampleTests.a in Frameworks */,
528AE9B4930F0DE7629654FA /* Pods_MessyExample_MessyExampleTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C80B921A6F3F58F76C31292 /* libPods-MessyExample.a in Frameworks */,
F17EB013D0B7C820D2EE5086 /* Pods_MessyExample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -100,8 +100,8 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-MessyExample.a */,
19F6CBCC0A4E27FBF8BF4A61 /* libPods-MessyExample-MessyExampleTests.a */,
234C33D5E1A5F2A618956A88 /* Pods_MessyExample.framework */,
5AC67C5C7E909C1F9F374F97 /* Pods_MessyExample_MessyExampleTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -564,6 +564,17 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
Expand Down Expand Up @@ -637,6 +648,17 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
Expand Down
4 changes: 4 additions & 0 deletions example/ios/MessyExample/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>need camera to take photo</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSPhotoLibraryUsageDescription</key>
<string>need photo to send image and video</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
57 changes: 44 additions & 13 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/scripts/react_native_pods.rb",
{paths: [process.argv[1]]},
)', __dir__]).strip

def node_require(script)
# Resolve script with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
"require.resolve(
'#{script}',
{paths: [process.argv[1]]},
)", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')
platform :ios, min_ios_version_supported
prepare_react_native_project!


setup_permissions([
# 'AppTrackingTransparency',
# 'Bluetooth',
# 'Calendars',
# 'CalendarsWriteOnly',
'Camera',
# 'Contacts',
# 'FaceID',
# 'LocationAccuracy',
# 'LocationAlways',
# 'LocationWhenInUse',
# 'MediaLibrary',
# 'Microphone',
# 'Motion',
# 'Notifications',
'PhotoLibrary',
# 'PhotoLibraryAddOnly',
# 'Reminders',
# 'Siri',
# 'SpeechRecognition',
# 'StoreKit',
])

# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
#
Expand All @@ -17,15 +46,17 @@ prepare_react_native_project!
# dependencies: {
# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
# ```
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
# flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
# linkage = ENV['USE_FRAMEWORKS']
# if linkage != nil
# Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
# use_frameworks! :linkage => linkage.to_sym
# end
use_frameworks! :linkage => :static

target 'MessyExample' do
$RNVideoUseVideoCaching=true
config = use_native_modules!

use_react_native!(
Expand All @@ -34,7 +65,7 @@ target 'MessyExample' do
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
:flipper_configuration => flipper_config,
:flipper_configuration => FlipperConfiguration.disabled,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
Expand Down
Loading

0 comments on commit 5608b90

Please sign in to comment.