Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
RocketChat
Rocket.Chat.ReactNative
Commits
f32a8910
Unverified
Commit
f32a8910
authored
Jan 14, 2021
by
Gerzon Z
Committed by
GitHub
Jan 14, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into improve.serveritem-usage
parents
510bb85a
03302198
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
3776 additions
and
3589 deletions
+3776
-3589
__tests__/__snapshots__/Storyshots.test.js.snap
__tests__/__snapshots__/Storyshots.test.js.snap
+3607
-3378
android/app/build.gradle
android/app/build.gradle
+1
-1
android/app/src/main/java/chat/rocket/reactnative/MainActivity.java
...p/src/main/java/chat/rocket/reactnative/MainActivity.java
+0
-56
app/containers/ThreadDetails.js
app/containers/ThreadDetails.js
+103
-0
app/containers/message/Thread.js
app/containers/message/Thread.js
+15
-20
app/containers/message/styles.js
app/containers/message/styles.js
+4
-0
app/lib/encryption/constants.js
app/lib/encryption/constants.js
+0
-1
app/lib/userPreferences.js
app/lib/userPreferences.js
+0
-21
app/sagas/login.js
app/sagas/login.js
+2
-28
app/views/ThreadMessagesView/Item.js
app/views/ThreadMessagesView/Item.js
+28
-54
app/views/ThreadMessagesView/index.js
app/views/ThreadMessagesView/index.js
+12
-0
ios/RocketChatRN.xcodeproj/project.pbxproj
ios/RocketChatRN.xcodeproj/project.pbxproj
+2
-2
ios/RocketChatRN/AppDelegate.m
ios/RocketChatRN/AppDelegate.m
+0
-21
ios/RocketChatRN/Info.plist
ios/RocketChatRN/Info.plist
+1
-1
ios/ShareRocketChatRN/Info.plist
ios/ShareRocketChatRN/Info.plist
+1
-1
storybook/stories/Message.js
storybook/stories/Message.js
+0
-5
No files found.
__tests__/__snapshots__/Storyshots.test.js.snap
View file @
f32a8910
This diff is collapsed.
Click to expand it.
android/app/build.gradle
View file @
f32a8910
...
...
@@ -144,7 +144,7 @@ android {
minSdkVersion
rootProject
.
ext
.
minSdkVersion
targetSdkVersion
rootProject
.
ext
.
targetSdkVersion
versionCode
VERSIONCODE
as
Integer
versionName
"4.1
3.1
"
versionName
"4.1
4.0
"
vectorDrawables
.
useSupportLibrary
=
true
if
(!
isFoss
)
{
manifestPlaceholders
=
[
BugsnagAPIKey:
BugsnagAPIKey
as
String
]
...
...
android/app/src/main/java/chat/rocket/reactnative/MainActivity.java
View file @
f32a8910
...
...
@@ -14,7 +14,6 @@ import com.facebook.react.ReactFragmentActivity;
import
com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView
;
import
com.zoontek.rnbootsplash.RNBootSplash
;
import
com.tencent.mmkv.MMKV
;
import
com.google.gson.Gson
;
class
ThemePreferences
{
...
...
@@ -36,61 +35,6 @@ public class MainActivity extends ReactFragmentActivity {
// https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067
super
.
onCreate
(
null
);
RNBootSplash
.
init
(
R
.
drawable
.
launch_screen
,
MainActivity
.
this
);
MMKV
.
initialize
(
MainActivity
.
this
);
// Start the MMKV container
MMKV
defaultMMKV
=
MMKV
.
defaultMMKV
();
boolean
alreadyMigrated
=
defaultMMKV
.
decodeBool
(
"alreadyMigrated"
);
if
(!
alreadyMigrated
)
{
// MMKV Instance that will be used by JS
MMKV
mmkv
=
MMKV
.
mmkvWithID
(
"default"
);
// SharedPreferences -> MMKV (Migration)
SharedPreferences
sharedPreferences
=
getSharedPreferences
(
"react-native"
,
Context
.
MODE_PRIVATE
);
mmkv
.
importFromSharedPreferences
(
sharedPreferences
);
// SharedPreferences only save strings, so we saved this value as a String and now we'll need to cast into a MMKV object
// Theme preferences object
String
THEME_PREFERENCES_KEY
=
"RC_THEME_PREFERENCES_KEY"
;
String
themeJson
=
sharedPreferences
.
getString
(
THEME_PREFERENCES_KEY
,
""
);
if
(!
themeJson
.
isEmpty
())
{
ThemePreferences
themePreferences
=
new
Gson
().
fromJson
(
themeJson
,
ThemePreferences
.
class
);
WritableMap
themeMap
=
new
Arguments
().
createMap
();
themeMap
.
putString
(
"currentTheme"
,
themePreferences
.
currentTheme
);
themeMap
.
putString
(
"darkLevel"
,
themePreferences
.
darkLevel
);
Bundle
bundle
=
Arguments
.
toBundle
(
themeMap
);
mmkv
.
encode
(
THEME_PREFERENCES_KEY
,
bundle
);
}
// Sort preferences object
String
SORT_PREFS_KEY
=
"RC_SORT_PREFS_KEY"
;
String
sortJson
=
sharedPreferences
.
getString
(
SORT_PREFS_KEY
,
""
);
if
(!
sortJson
.
isEmpty
())
{
SortPreferences
sortPreferences
=
new
Gson
().
fromJson
(
sortJson
,
SortPreferences
.
class
);
WritableMap
sortMap
=
new
Arguments
().
createMap
();
sortMap
.
putString
(
"sortBy"
,
sortPreferences
.
sortBy
);
if
(
sortPreferences
.
groupByType
!=
null
)
{
sortMap
.
putBoolean
(
"groupByType"
,
sortPreferences
.
groupByType
);
}
if
(
sortPreferences
.
showFavorites
!=
null
)
{
sortMap
.
putBoolean
(
"showFavorites"
,
sortPreferences
.
showFavorites
);
}
if
(
sortPreferences
.
showUnread
!=
null
)
{
sortMap
.
putBoolean
(
"showUnread"
,
sortPreferences
.
showUnread
);
}
Bundle
bundle
=
Arguments
.
toBundle
(
sortMap
);
mmkv
.
encode
(
SORT_PREFS_KEY
,
bundle
);
}
// Remove all our keys of SharedPreferences
sharedPreferences
.
edit
().
clear
().
commit
();
// Mark migration complete
defaultMMKV
.
encode
(
"alreadyMigrated"
,
true
);
}
}
/**
...
...
app/containers/ThreadDetails.js
0 → 100644
View file @
f32a8910
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
{
View
,
Text
,
StyleSheet
}
from
'
react-native
'
;
import
Touchable
from
'
react-native-platform-touchable
'
;
import
{
CustomIcon
}
from
'
../lib/Icons
'
;
import
{
themes
}
from
'
../constants/colors
'
;
import
sharedStyles
from
'
../views/Styles
'
;
import
{
withTheme
}
from
'
../theme
'
;
const
styles
=
StyleSheet
.
create
({
container
:
{
flex
:
1
,
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
},
detailsContainer
:
{
flex
:
1
,
flexDirection
:
'
row
'
},
detailContainer
:
{
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
,
marginRight
:
8
},
detailText
:
{
fontSize
:
10
,
marginLeft
:
2
,
...
sharedStyles
.
textSemibold
},
badgeContainer
:
{
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
},
badge
:
{
width
:
8
,
height
:
8
,
borderRadius
:
4
,
marginRight
:
8
}
});
const
ThreadDetails
=
({
item
,
user
,
badgeColor
,
toggleFollowThread
,
style
,
theme
})
=>
{
let
{
tcount
}
=
item
;
if
(
tcount
>=
1000
)
{
tcount
=
'
+999
'
;
}
else
if
(
tcount
>=
100
)
{
tcount
=
'
+99
'
;
}
let
replies
=
item
?.
replies
?.
length
??
0
;
if
(
replies
>=
1000
)
{
replies
=
'
+999
'
;
}
else
if
(
replies
>=
100
)
{
replies
=
'
+99
'
;
}
const
isFollowing
=
item
.
replies
?.
find
(
u
=>
u
===
user
?.
id
);
return
(
<
View
style
=
{[
styles
.
container
,
style
]}
>
<
View
style
=
{
styles
.
detailsContainer
}
>
<
View
style
=
{
styles
.
detailContainer
}
>
<
CustomIcon
name
=
'
threads
'
size
=
{
24
}
color
=
{
themes
[
theme
].
auxiliaryText
}
/
>
<
Text
style
=
{[
styles
.
detailText
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
numberOfLines
=
{
1
}
>
{
tcount
}
<
/Text
>
<
/View
>
<
View
style
=
{
styles
.
detailContainer
}
>
<
CustomIcon
name
=
'
user
'
size
=
{
24
}
color
=
{
themes
[
theme
].
auxiliaryText
}
/
>
<
Text
style
=
{[
styles
.
detailText
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
numberOfLines
=
{
1
}
>
{
replies
}
<
/Text
>
<
/View
>
<
/View
>
<
View
style
=
{
styles
.
badgeContainer
}
>
{
badgeColor
?
<
View
style
=
{[
styles
.
badge
,
{
backgroundColor
:
badgeColor
}]}
/> : null
}
<
Touchable
onPress
=
{()
=>
toggleFollowThread
?.(
isFollowing
,
item
.
id
)}
>
<
CustomIcon
size
=
{
24
}
name
=
{
isFollowing
?
'
notification
'
:
'
notification-disabled
'
}
color
=
{
themes
[
theme
].
auxiliaryTintColor
}
/
>
<
/Touchable
>
<
/View
>
<
/View
>
);
};
ThreadDetails
.
propTypes
=
{
item
:
PropTypes
.
object
,
user
:
PropTypes
.
object
,
badgeColor
:
PropTypes
.
string
,
toggleFollowThread
:
PropTypes
.
func
,
style
:
PropTypes
.
object
,
theme
:
PropTypes
.
string
};
export
default
withTheme
(
ThreadDetails
);
app/containers/message/Thread.js
View file @
f32a8910
import
React
,
{
useContext
}
from
'
react
'
;
import
{
View
,
Text
}
from
'
react-native
'
;
import
PropTypes
from
'
prop-types
'
;
import
Touchable
from
'
react-native-platform-touchable
'
;
import
{
formatMessageCount
}
from
'
./utils
'
;
import
styles
from
'
./styles
'
;
import
{
CustomIcon
}
from
'
../../lib/Icons
'
;
import
{
THREAD
}
from
'
./constants
'
;
import
{
themes
}
from
'
../../constants/colors
'
;
import
{
formatDateThreads
}
from
'
../../utils/room
'
;
import
MessageContext
from
'
./Context
'
;
import
ThreadDetails
from
'
../ThreadDetails
'
;
import
I18n
from
'
../../i18n
'
;
const
Thread
=
React
.
memo
(({
msg
,
tcount
,
tlm
,
isThreadRoom
,
theme
,
id
...
...
@@ -21,28 +18,26 @@ const Thread = React.memo(({
const
{
threadBadgeColor
,
toggleFollowThread
,
user
,
replies
}
=
useContext
(
MessageContext
);
const
time
=
formatDateThreads
(
tlm
);
const
buttonText
=
formatMessageCount
(
tcount
,
THREAD
);
const
isFollowing
=
replies
?.
find
(
u
=>
u
===
user
.
id
);
return
(
<
View
style
=
{
styles
.
buttonContainer
}
>
<
View
style
=
{[
styles
.
button
,
{
backgroundColor
:
themes
[
theme
].
tintColor
}]}
testID
=
{
`message-thread-button-
${
msg
}
`
}
>
<
CustomIcon
name
=
'
threads
'
size
=
{
16
}
style
=
{[
styles
.
buttonIcon
,
{
color
:
themes
[
theme
].
buttonText
}]}
/
>
<
Text
style
=
{[
styles
.
buttonText
,
{
color
:
themes
[
theme
].
buttonText
}]}
>
{
buttonText
}
<
/Text
>
<
Text
style
=
{[
styles
.
buttonText
,
{
color
:
themes
[
theme
].
buttonText
}]}
>
{
I18n
.
t
(
'
Reply
'
)}
<
/Text
>
<
/View
>
<
Text
style
=
{[
styles
.
time
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
>
{
time
}
<
/Text
>
{
threadBadgeColor
?
<
View
style
=
{[
styles
.
threadBadge
,
{
backgroundColor
:
threadBadgeColor
}]}
/> : null
}
<
Touchable
onPress
=
{()
=>
toggleFollowThread
(
isFollowing
,
id
)}
>
<
CustomIcon
name
=
{
isFollowing
?
'
notification
'
:
'
notification-disabled
'
}
size
=
{
24
}
color
=
{
themes
[
theme
].
auxiliaryText
}
style
=
{
styles
.
threadBell
}
/
>
<
/Touchable
>
<
ThreadDetails
item
=
{{
tcount
,
replies
,
tlm
,
id
}}
user
=
{
user
}
badgeColor
=
{
threadBadgeColor
}
toggleFollowThread
=
{
toggleFollowThread
}
style
=
{
styles
.
threadDetails
}
/
>
<
/View
>
);
},
(
prevProps
,
nextProps
)
=>
{
...
...
app/containers/message/styles.js
View file @
f32a8910
...
...
@@ -176,5 +176,9 @@ export default StyleSheet.create({
},
encrypted
:
{
justifyContent
:
'
center
'
},
threadDetails
:
{
flex
:
1
,
marginLeft
:
12
}
});
app/lib/encryption/constants.js
View file @
f32a8910
...
...
@@ -2,7 +2,6 @@ export const E2E_MESSAGE_TYPE = 'e2e';
export
const
E2E_PUBLIC_KEY
=
'
RC_E2E_PUBLIC_KEY
'
;
export
const
E2E_PRIVATE_KEY
=
'
RC_E2E_PRIVATE_KEY
'
;
export
const
E2E_RANDOM_PASSWORD_KEY
=
'
RC_E2E_RANDOM_PASSWORD_KEY
'
;
export
const
E2E_REFRESH_MESSAGES_KEY
=
'
E2E_REFRESH_MESSAGES_KEY
'
;
export
const
E2E_STATUS
=
{
PENDING
:
'
pending
'
,
DONE
:
'
done
'
...
...
app/lib/userPreferences.js
View file @
f32a8910
import
MMKVStorage
from
'
react-native-mmkv-storage
'
;
import
log
from
'
../utils/log
'
;
const
MMKV
=
new
MMKVStorage
.
Loader
()
// MODES.MULTI_PROCESS = ACCESSIBLE BY APP GROUP (iOS)
.
setProcessingMode
(
MMKVStorage
.
MODES
.
MULTI_PROCESS
)
...
...
@@ -11,25 +9,6 @@ const MMKV = new MMKVStorage.Loader()
class
UserPreferences
{
constructor
()
{
this
.
mmkv
=
MMKV
;
this
.
encryptMigratedData
();
}
// It should run only once
async
encryptMigratedData
()
{
try
{
const
encryptMigration
=
await
this
.
getBoolAsync
(
'
encryptMigration
'
);
if
(
!
encryptMigration
)
{
// Encrypt the migrated data
await
this
.
mmkv
.
encryption
.
encrypt
();
// Mark as completed
await
this
.
setBoolAsync
(
'
encryptMigration
'
,
true
);
}
}
catch
(
e
)
{
log
(
e
);
}
}
async
getStringAsync
(
key
)
{
...
...
app/sagas/login.js
View file @
f32a8910
...
...
@@ -31,7 +31,6 @@ import UserPreferences from '../lib/userPreferences';
import
{
inquiryRequest
,
inquiryReset
}
from
'
../ee/omnichannel/actions/inquiry
'
;
import
{
isOmnichannelStatusAvailable
}
from
'
../ee/omnichannel/lib
'
;
import
{
E2E_REFRESH_MESSAGES_KEY
}
from
'
../lib/encryption/constants
'
;
import
Navigation
from
'
../lib/Navigation
'
;
const
getServer
=
state
=>
state
.
server
.
server
;
...
...
@@ -120,32 +119,7 @@ const fetchEnterpriseModules = function* fetchEnterpriseModules({ user }) {
}
};
const
fetchRooms
=
function
*
fetchRooms
({
server
})
{
try
{
// Read the flag to check if refresh was already done
const
refreshed
=
yield
UserPreferences
.
getBoolAsync
(
E2E_REFRESH_MESSAGES_KEY
);
if
(
!
refreshed
)
{
const
serversDB
=
database
.
servers
;
const
serversCollection
=
serversDB
.
collections
.
get
(
'
servers
'
);
const
serverRecord
=
yield
serversCollection
.
find
(
server
);
// We need to reset roomsUpdatedAt to request all rooms again
// and save their respective E2EKeys to decrypt all pending messages and lastMessage
// that are already inserted on local database by other app version
yield
serversDB
.
action
(
async
()
=>
{
await
serverRecord
.
update
((
s
)
=>
{
s
.
roomsUpdatedAt
=
null
;
});
});
// Set the flag to indicate that already refreshed
yield
UserPreferences
.
setBoolAsync
(
E2E_REFRESH_MESSAGES_KEY
,
true
);
}
}
catch
(
e
)
{
log
(
e
);
}
const
fetchRooms
=
function
*
fetchRooms
()
{
yield
put
(
roomsRequest
());
};
...
...
@@ -157,7 +131,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
RocketChat
.
getUserPresence
(
user
.
id
);
const
server
=
yield
select
(
getServer
);
yield
fork
(
fetchRooms
,
{
server
}
);
yield
fork
(
fetchRooms
);
yield
fork
(
fetchPermissions
);
yield
fork
(
fetchCustomEmojis
);
yield
fork
(
fetchRoles
);
...
...
app/views/ThreadMessagesView/Item.js
View file @
f32a8910
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
{
View
,
Text
,
StyleSheet
}
from
'
react-native
'
;
import
Touchable
from
'
react-native-platform-touchable
'
;
import
{
withTheme
}
from
'
../../theme
'
;
import
Avatar
from
'
../../containers/Avatar
'
;
import
Touch
from
'
../../utils/touch
'
;
import
sharedStyles
from
'
../Styles
'
;
import
{
themes
}
from
'
../../constants/colors
'
;
import
Markdown
from
'
../../containers/markdown
'
;
import
{
CustomIcon
}
from
'
../../lib/Icons
'
;
import
{
formatDateThreads
,
makeThreadName
}
from
'
../../utils/room
'
;
import
ThreadDetails
from
'
../../containers/ThreadDetails
'
;
const
styles
=
StyleSheet
.
create
({
container
:
{
...
...
@@ -38,34 +38,26 @@ const styles = StyleSheet.create({
avatar
:
{
marginRight
:
8
},
detailsContainer
:
{
marginTop
:
8
,
flexDirection
:
'
row
'
},
detailContainer
:
{
marginRight
:
8
,
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
,
justifyContent
:
'
center
'
threadDetails
:
{
marginTop
:
8
},
detailText
:
{
fontSize
:
10
,
marginLeft
:
2
,
...
sharedStyles
.
textSemibold
badge
:
{
width
:
8
,
height
:
8
,
borderRadius
:
4
,
marginHorizontal
:
8
,
alignSelf
:
'
center
'
},
badgeContainer
:
{
marginLeft
:
8
,
justifyContent
:
'
center
'
messageContainer
:
{
flexDirection
:
'
row
'
},
badge
:
{
width
:
12
,
height
:
12
,
borderRadius
:
6
markdown
:
{
flex
:
1
}
});
const
Item
=
({
item
,
baseUrl
,
theme
,
useRealName
,
user
,
badgeColor
,
onPress
item
,
baseUrl
,
theme
,
useRealName
,
user
,
badgeColor
,
onPress
,
toggleFollowThread
})
=>
{
const
username
=
(
useRealName
&&
item
?.
u
?.
name
)
||
item
?.
u
?.
username
;
let
time
;
...
...
@@ -73,13 +65,8 @@ const Item = ({
time
=
formatDateThreads
(
item
.
ts
);
}
let
tlm
;
if
(
item
?.
tlm
)
{
tlm
=
formatDateThreads
(
item
.
tlm
);
}
return
(
<
Touch
theme
=
{
theme
}
onPress
=
{()
=>
onPress
(
item
)}
testID
=
{
`thread-messages-view-
${
item
.
msg
}
`
}
style
=
{{
backgroundColor
:
themes
[
theme
].
backgroundColor
}}
>
<
Touch
able
onPress
=
{()
=>
onPress
(
item
)}
testID
=
{
`thread-messages-view-
${
item
.
msg
}
`
}
style
=
{{
backgroundColor
:
themes
[
theme
].
backgroundColor
}}
>
<
View
style
=
{
styles
.
container
}
>
<
Avatar
style
=
{
styles
.
avatar
}
...
...
@@ -96,33 +83,19 @@ const Item = ({
<
Text
style
=
{[
styles
.
title
,
{
color
:
themes
[
theme
].
titleText
}]}
numberOfLines
=
{
1
}
>
{
username
}
<
/Text
>
<
Text
style
=
{[
styles
.
time
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
>
{
time
}
<
/Text
>
<
/View
>
<
Markdown
msg
=
{
makeThreadName
(
item
)}
baseUrl
=
{
baseUrl
}
username
=
{
username
}
theme
=
{
theme
}
numberOfLines
=
{
2
}
preview
/>
<
View
style
=
{
styles
.
detailsContainer
}
>
<
View
style
=
{
styles
.
detailContainer
}
>
<
CustomIcon
name
=
'
threads
'
size
=
{
20
}
color
=
{
themes
[
theme
].
auxiliaryText
}
/
>
<
Text
style
=
{[
styles
.
detailText
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
>
{
item
?.
tcount
}
<
/Text
>
<
/View
>
<
View
style
=
{
styles
.
detailContainer
}
>
<
CustomIcon
name
=
'
user
'
size
=
{
20
}
color
=
{
themes
[
theme
].
auxiliaryText
}
/
>
<
Text
style
=
{[
styles
.
detailText
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
>
{
item
?.
replies
?.
length
}
<
/Text
>
<
/View
>
<
View
style
=
{
styles
.
detailContainer
}
>
<
CustomIcon
name
=
'
clock
'
size
=
{
20
}
color
=
{
themes
[
theme
].
auxiliaryText
}
/
>
<
Text
style
=
{[
styles
.
detailText
,
{
color
:
themes
[
theme
].
auxiliaryText
}]}
>
{
tlm
}
<
/Text
>
<
/View
>
<
View
style
=
{
styles
.
messageContainer
}
>
<
Markdown
msg
=
{
makeThreadName
(
item
)}
baseUrl
=
{
baseUrl
}
username
=
{
username
}
theme
=
{
theme
}
numberOfLines
=
{
2
}
style
=
{[
styles
.
markdown
]}
preview
/>
{
badgeColor
?
<
View
style
=
{[
styles
.
badge
,
{
backgroundColor
:
badgeColor
}]}
/> : null
}
<
/View
>
<
ThreadDetails
item
=
{
item
}
user
=
{
user
}
toggleFollowThread
=
{
toggleFollowThread
}
style
=
{
styles
.
threadDetails
}
/
>
<
/View
>
{
badgeColor
?
(
<
View
style
=
{
styles
.
badgeContainer
}
>
<
View
style
=
{[
styles
.
badge
,
{
backgroundColor
:
badgeColor
}]}
/
>
<
/View
>
)
:
null
}
<
/View
>
<
/Touch
>
<
/Touch
able
>
);
};
...
...
@@ -133,7 +106,8 @@ Item.propTypes = {
useRealName
:
PropTypes
.
bool
,
user
:
PropTypes
.
object
,
badgeColor
:
PropTypes
.
string
,
onPress
:
PropTypes
.
func
onPress
:
PropTypes
.
func
,
toggleFollowThread
:
PropTypes
.
func
};
export
default
withTheme
(
Item
);
app/views/ThreadMessagesView/index.js
View file @
f32a8910
...
...
@@ -33,6 +33,8 @@ import { isIOS } from '../../utils/deviceInfo';
import
{
getBadgeColor
,
makeThreadName
}
from
'
../../utils/room
'
;
import
{
getHeaderTitlePosition
}
from
'
../../containers/Header
'
;
import
SearchHeader
from
'
./SearchHeader
'
;
import
EventEmitter
from
'
../../utils/events
'
;
import
{
LISTENER
}
from
'
../../containers/Toast
'
;
const
API_FETCH_COUNT
=
50
;
...
...
@@ -410,6 +412,15 @@ class ThreadMessagesView extends React.Component {
this
.
setState
({
currentFilter
:
filter
,
displayingThreads
});
}
toggleFollowThread
=
async
(
isFollowingThread
,
tmid
)
=>
{
try
{
await
RocketChat
.
toggleFollowMessage
(
tmid
,
!
isFollowingThread
);
EventEmitter
.
emit
(
LISTENER
,
{
message
:
isFollowingThread
?
I18n
.
t
(
'
Unfollowed_thread
'
)
:
I18n
.
t
(
'
Following_thread
'
)
});
}
catch
(
e
)
{
log
(
e
);
}
}
renderItem
=
({
item
})
=>
{
const
{
user
,
navigation
,
baseUrl
,
useRealName
...
...
@@ -426,6 +437,7 @@ class ThreadMessagesView extends React.Component {
badgeColor
}}
onPress
=
{
this
.
onThreadPress
}
toggleFollowThread
=
{
this
.
toggleFollowThread
}
/
>
);
}
...
...
ios/RocketChatRN.xcodeproj/project.pbxproj
View file @
f32a8910
...
...
@@ -1717,7 +1717,7 @@
INFOPLIST_FILE
=
NotificationService/Info.plist
;
IPHONEOS_DEPLOYMENT_TARGET
=
11.0
;
LD_RUNPATH_SEARCH_PATHS
=
"$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"
;
MARKETING_VERSION
=
4.1
3.1
;
MARKETING_VERSION
=
4.1
4.0
;
MTL_ENABLE_DEBUG_INFO
=
INCLUDE_SOURCE
;
MTL_FAST_MATH
=
YES
;
PRODUCT_BUNDLE_IDENTIFIER
=
chat.rocket.reactnative.NotificationService
;
...
...
@@ -1754,7 +1754,7 @@
INFOPLIST_FILE
=
NotificationService/Info.plist
;
IPHONEOS_DEPLOYMENT_TARGET
=
11.0
;
LD_RUNPATH_SEARCH_PATHS
=
"$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"
;
MARKETING_VERSION
=
4.1
3.1
;
MARKETING_VERSION
=
4.1
4.0
;
MTL_FAST_MATH
=
YES
;
PRODUCT_BUNDLE_IDENTIFIER
=
chat.rocket.reactnative.NotificationService
;
PRODUCT_NAME
=
"$(TARGET_NAME)"
;
...
...
ios/RocketChatRN/AppDelegate.m
View file @
f32a8910
...
...
@@ -69,27 +69,6 @@ static void InitializeFlipper(UIApplication *application) {
// AppGroup MMKV
NSString
*
groupDir
=
[[
NSFileManager
defaultManager
]
containerURLForSecurityApplicationGroupIdentifier
:[[
NSBundle
mainBundle
]
objectForInfoDictionaryKey
:
@"AppGroup"
]].
path
;
[
MMKV
initializeMMKV
:
nil
groupDir
:
groupDir
logLevel
:
MMKVLogNone
];
// Start the MMKV container
MMKV
*
defaultMMKV
=
[
MMKV
mmkvWithID
:
@"migration"
mode
:
MMKVMultiProcess
];
BOOL
alreadyMigrated
=
[
defaultMMKV
getBoolForKey
:
@"alreadyMigrated"
];
if
(
!
alreadyMigrated
)
{
// MMKV Instance that will be used by JS
MMKV
*
mmkv
=
[
MMKV
mmkvWithID
:
@"default"
mode
:
MMKVMultiProcess
];
// NSUserDefaults -> MMKV (Migration)
NSUserDefaults
*
userDefaults
=
[[
NSUserDefaults
alloc
]
initWithSuiteName
:[[
NSBundle
mainBundle
]
objectForInfoDictionaryKey
:
@"AppGroup"
]];
[
mmkv
migrateFromUserDefaults
:
userDefaults
];
// Remove our own keys of NSUserDefaults
for
(
NSString
*
key
in
[
userDefaults
dictionaryRepresentation
].
keyEnumerator
)
{
[
userDefaults
removeObjectForKey
:
key
];
}
// Mark migration complete
[
defaultMMKV
setBool
:
YES
forKey
:
@"alreadyMigrated"
];
}
return
YES
;
}
...
...
ios/RocketChatRN/Info.plist
View file @
f32a8910
...
...
@@ -23,7 +23,7 @@
<key>
CFBundlePackageType
</key>
<string>
APPL
</string>
<key>
CFBundleShortVersionString
</key>
<string>
4.1
3.1
</string>
<string>
4.1
4.0
</string>
<key>
CFBundleSignature
</key>
<string>
????
</string>
<key>
CFBundleURLTypes
</key>
...
...
ios/ShareRocketChatRN/Info.plist
View file @
f32a8910
...
...
@@ -19,7 +19,7 @@
<key>
CFBundlePackageType
</key>
<string>
XPC!
</string>
<key>
CFBundleShortVersionString
</key>
<string>
4.1
3.1
</string>
<string>
4.1
4.0
</string>
<key>
CFBundleVersion
</key>
<string>
1
</string>
<key>
KeychainGroup
</key>
...
...
storybook/stories/Message.js
View file @
f32a8910
...
...
@@ -469,11 +469,6 @@ export default ({ theme }) => {
tcount
=
{
1
}
tlm
=
{
date
}
/
>
<
Message
msg
=
'
How are you?
'
tcount
=
{
9999
}
tlm
=
{
date
}
/
>
<
Message
msg
=
"
I'm fine!
"
tmid
=
'
1
'