diff --git a/__mocks__/expo-keep-awake.js b/__mocks__/expo-keep-awake.js
index 947b94723..4df99a606 100644
--- a/__mocks__/expo-keep-awake.js
+++ b/__mocks__/expo-keep-awake.js
@@ -1,4 +1,4 @@
-export default {
- activateKeepAwake: () => '',
- deactivateKeepAwake: () => ''
-};
+const activateKeepAwake = () => '';
+const deactivateKeepAwake = () => '';
+
+export { activateKeepAwake, deactivateKeepAwake };
diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index 299d099a4..c27e4dce0 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -628,7 +628,59 @@ exports[`Storyshots Avatar list Avatar 1`] = `
undefined,
]
}
- />
+ >
+
+
+
+
+
+
`;
+exports[`Storyshots List header 1`] = `
+
+
+
+
+ Chats
+
+
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
+
+`;
+
+exports[`Storyshots List icon 1`] = `
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List pressable 1`] = `
+
+
+
+ View
+
+ View
+
+
+
+`;
+
+exports[`Storyshots List separator 1`] = `
+
+
+
+
+
+`;
+
+exports[`Storyshots List title and subtitle 1`] = `
+
+
+
+
+
+
+
+ Chats
+
+
+
+
+
+
+
+
+
+ Chats
+
+
+ All
+
+
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with FlatList 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with bigger font 1`] = `
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with black theme 1`] = `
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with custom color 1`] = `
+
+
+
+
+
+
+
+ Chats
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with dark theme 1`] = `
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with icon 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Icon Left
+
+
+
+
+
+
+
+
+
+ Icon Right
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show Action Indicator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with section and info 1`] = `
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+ Chats
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+ Chats
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+
+
+ Section Item
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+
+
+
+
+`;
+
+exports[`Storyshots List with small font 1`] = `
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+ Chats
+
+
+
+ View
+
+ View
+
+
+
+ Chats
+
+
+
+
+
+
+`;
+
exports[`Storyshots Markdown list Markdown 1`] = `
+ >
+
+
+
+
+
+
+
+
+ First Header
+
+
+
+
+
+
+ Second Header
+
+
+
+
+
+
+
+
+ Content from cell 1
+
+
+
+
+
+
+ Content from cell 2
+
+
+
+
+
+
+
+
+ Content in the first column
+
+
+
+
+
+
+ Content in the second column
+
+
+
+
+
+
+
+
+ Click to see full table
+
+
+
`;
@@ -4229,6 +8400,236 @@ exports[`Storyshots Message list message 1`] = `
>
Simple
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Long message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
Grouped messages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Different user
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is the third message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is the second message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ This is the first message
+
+
+
+
+
+
+
+
Without header
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
With alias
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Diego Mello
+
+ @
+ diego.mello
+
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Diego Mello
+
+ @
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Edited
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Encrypted
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Message Encrypted without Header
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+ Message Encrypted with Reactions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 😂
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ 🤔
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thread with emoji🙂 😂
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thread reply encrypted
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+ Temp message encrypted
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+ Message Edited encrypted
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+
+ diego.mello
+
+
10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+ Read Receipt encrypted with Header
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Read Receipt encrypted without Header
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Block Quote
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+ Testing block quote
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+ Testing block quote
+
+
+
+
+
+
+ Testing block quote
+
+
+
+
+
+
+
+
Lists
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+ •
+
+
+
+
+
+ Dogs
+
+
+
+
+
+ ◦
+
+
+
+
+
+ cats
+
+
+
+
+
+
+
+ ◦
+
+
+
+
+
+ cats
+
+
+
+
+
+
+
+
+
+
+
+
Numerated lists
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+ 1.
+
+
+
+
+
+ Dogs
+
+
+
+
+
+
+
+ 2.
+
+
+
+
+
+ Cats
+
+
+
+
+
+
+
+
+
+
Numerated lists in separated messages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+ 1.
+
+
+
+
+
+ Dogs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.
+
+
+
+
+
+ Cats
+
+
+
+
+
+
+
+
+
+
Static avatar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Full name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Diego Mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Mentions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ rocket.cat
+
+
+
+
+
+ diego.mello
+
+
+
+
+
+ all
+
+
+
+
+
+ here
+
+
+
+
+
+ #general
+
+
+
+
+
+
+
+
Emojis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ 👊🤙👏
+
+
+
+
+
+
+
+
Single Emoji
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ 👏
+
+
+
+
+
+
+
+
Custom Emojis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Single Custom Emojis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Normal Emoji + Custom Emojis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ 🤙
+
+
+
+
+
+
+
+
+
+
+
Four emoji
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ 🤙
+
+
+
+
+
+ 🤙🤙
+
+
+
+
+
+
+
+
Time format
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10 November 2017
+
+
+
+
+
+ Testing
+
+
+
+
+
+
+
+
Reactions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Reactions
+
+
+
+
+
+
+
+ 😂
+
+
+ 3
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+ 🤔
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Multiple reactions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Multiple Reactions
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ ❤️
+
+
+ 1
+
+
+
+
+
+
+ 🐶
+
+
+ 1
+
+
+
+
+
+
+ 😀
+
+
+ 1
+
+
+
+
+
+
+ 😬
+
+
+ 1
+
+
+
+
+
+
+ 😁
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Intercalated users
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Fourth message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Third message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Second message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ First message
+
+
+
+
+
+
+
+
Date and Unread separators
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Fourth message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Third message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Second message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Second message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ First message
+
+
+
+
+
+
+
+
With image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+ This is a description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+ This is a description
+
+
+
+
+
+
+
+
+
+
+
+
With video
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+ This is a description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
+
With audio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+ 00:00
+
+
+
+
+ This is a description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ First message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 00:00
+
+
+
+
+ This is a description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 00:00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 00:00
+
+
+
+
+
+
+
Message with reply
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+ I'm a very long long title and I'll break
+
+
+ 10:00 AM
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+ rocket.cat
+
+
+ 10:00 AM
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+
+
+
Message with read receipt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
Message with thread
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+ 1 reply
+
+
+
+ Nov 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+ +999 replies
+
+
+
+ Nov 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thread with emoji🙂 😂
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Markdown: link block code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thread with attachment
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sent an attachment
+
+
+
+
+
+
+
Sequential thread messages following thread button
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+ 1 reply
+
+
+
+ Nov 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sent an attachment
+
+
+
+
+
+
+
Sequential thread messages following thread reply
+
+
+
+
+
+
+
+
+ How are you?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I'm fine!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cool!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sent an attachment
+
+
+
+
+
+
+
Discussion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+ Started a discussion:
+
+
+ This is a discussion
+
+
+
+
+
+
+
+ No messages yet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+ Started a discussion:
+
+
+ This is a discussion
+
+
+
+
+
+
+
+ 1 message
+
+
+
+ Nov 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+ Started a discussion:
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+ 10 messages
+
+
+
+ Nov 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+ Started a discussion:
+
+
+ This is a discussion
+
+
+
+
+
+
+
+ +999 messages
+
+
+
+ Nov 10
+
+
+
+
+
+
+
URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+ Rocket.Chat - Free, Open Source, Enterprise Team Chat
+
+
+ Rocket.Chat is the leading open source team chat software solution. Free, unlimited and completely customizable with on-premises and SaaS cloud hosting.
+
+
+
+
+
+
+ Google
+
+
+ Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
+
+ Google
+
+
+ Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Google
+
+
+ Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.
+
+
+
+
+
+
+
+
Custom fields
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+ rocket.cat
+
+
+ 10:00 AM
+
+
+
+
+ Custom fields
+
+
+
+
+
+ Field 1
+
+
+ Value 1
+
+
+
+
+ Field 2
+
+
+ Value 2
+
+
+
+
+ Field 3
+
+
+ Value 3
+
+
+
+
+ Field 4
+
+
+ Value 4
+
+
+
+
+ Field 5
+
+
+ Value 5
+
+
+
+
+
+
+
+
+
+
Two short custom fields
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+ rocket.cat
+
+
+ 10:00 AM
+
+
+
+
+ Custom fields
+
+
+
+
+
+ Field 1
+
+
+ Value 1
+
+
+
+
+ Field 2
+
+
+ Value 2
+
+
+
+
+
+
+
+
+
+ rocket.cat
+
+
+ 10:00 AM
+
+
+
+
+ Custom fields 2
+
+
+
+
+
+ Field 1
+
+
+ Value 1
+
+
+
+
+ Field 2
+
+
+ Value 2
+
+
+
+
+
+
+
+
+
+
Broadcast
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Broadcasted message
+
+
+
+
+
+
+
+
+
+ Reply
+
+
+
+
+
+
+
+
Archived
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ This message is inside an archived room
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+
+ diego.mello
+
+
10:00 AM
+
+
+
+
+
+
+
+ diego.mello
+
+
10:00 AM
+
+
+
+
+
Temp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Temp message
+
+
+
+
+
+
+
+
Editing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message being edited
+
+
+
+
+
+
+
+
Removed
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Message removed
+
+
+
+
+
+
Joined
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Has joined the channel
+
+
+
+
+
+
Room name changed
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Room name changed to: New name by diego.mello
+
+
+
+
+
+
Message pinned
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Message pinned
+
+
+
+
+
+
Has left the channel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Has left the channel
+
+
+
+
+
+
User removed
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User rocket.cat removed by diego.mello
+
+
+
+
+
+
User added
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User rocket.cat added by diego.mello
+
+
+
+
+
+
User muted
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User rocket.cat muted by diego.mello
+
+
+
+
+
+
User unmuted
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User rocket.cat unmuted by diego.mello
+
+
+
+
+
+
Role added
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat was set admin by diego.mello
+
+
+
+
+
+
Role removed
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rocket.cat is no longer admin by diego.mello
+
+
+
+
+
+
Changed description
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Room description changed to: new description by diego.mello
+
+
+
+
+
+
Changed announcement
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Room announcement changed to: new announcement by diego.mello
+
+
+
+
+
+
Changed topic
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Room topic changed to: new topic by diego.mello
+
+
+
+
+
+
Changed type
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Room type changed to: public by diego.mello
+
+
+
+
+
+
Custom style
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Message
+
+
+
+
+
+
+
+
Markdown emphasis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Italic with single
+
+
+ underscore
+
+
+ or double
+
+
+ underscores
+
+
+ . Bold with single
+
+
+ asterisk
+
+
+ or double
+
+
+ asterisks
+
+
+ . Strikethrough with single
+
+
+ Strikethrough
+
+
+ or double
+
+
+ Strikethrough
+
+
+
+
+
+
+
+
Markdown headers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ H1
+
+
+
+
+ H2
+
+
+
+
+ H3
+
+
+
+
+ H4
+
+
+
+
+ H5
+
+
+
+
+ H6
+
+
+
+
+
+
+
+
Markdown links
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Support
+
+
+
+ Google
+
+
+
+
+
+
+
+ I\`m an inline-style link
+
+
+
+
+
+
+
+ https://google.com
+
+
+
+
+
+
+
+
+
Markdown image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+
Markdown code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+ Inline
+
+
+ code
+
+
+ has
+
+
+ back-ticks around
+
+
+ it.
+
+
+
+ Code block
+
+
+
+
+
+
+
+
Markdown quote
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+ Quote
+
+
+
+
+
+
+
+
+
+
Markdown table
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ diego.mello
+
+
+
+ 10:00 AM
+
+
+
+
+
+
+
+
+
+
+
+ First Header
+
+
+
+
+
+
+ Second Header
+
+
+
+
+
+
+
+
+ Content from cell 1
+
+
+
+
+
+
+ Content from cell 2
+
+
+
+
+
+
+
+
+ Content in the first column
+
+
+
+
+
+
+ Content in the second column
+
+
+
+
+
+
+
+
+ Click to see full table
+
+
+
+
+
+
+
+
`;
diff --git a/app/containers/ActionSheet/ActionSheet.js b/app/containers/ActionSheet/ActionSheet.js
index f7c009368..81b3496ae 100644
--- a/app/containers/ActionSheet/ActionSheet.js
+++ b/app/containers/ActionSheet/ActionSheet.js
@@ -27,7 +27,7 @@ import { Button } from './Button';
import { themes } from '../../constants/colors';
import styles, { ITEM_HEIGHT } from './styles';
import { isTablet, isIOS } from '../../utils/deviceInfo';
-import Separator from '../Separator';
+import * as List from '../List';
import I18n from '../../i18n';
import { useOrientation, useDimensions } from '../../dimensions';
@@ -142,8 +142,6 @@ const ActionSheet = React.memo(forwardRef(({ children, theme }, ref) => {
) : null));
- const renderSeparator = useCallback(() => );
-
const renderItem = useCallback(({ item }) => );
const animatedPosition = React.useRef(new Value(0));
@@ -191,8 +189,8 @@ const ActionSheet = React.memo(forwardRef(({ children, theme }, ref) => {
keyExtractor={item => item.title}
style={{ backgroundColor: themes[theme].focusedBackground }}
contentContainerStyle={styles.content}
- ItemSeparatorComponent={renderSeparator}
- ListHeaderComponent={renderSeparator}
+ ItemSeparatorComponent={List.Separator}
+ ListHeaderComponent={List.Separator}
ListFooterComponent={renderFooter}
getItemLayout={getItemLayout}
removeClippedSubviews={isIOS}
diff --git a/app/containers/DisclosureIndicator.js b/app/containers/DisclosureIndicator.js
deleted file mode 100644
index e33dbe816..000000000
--- a/app/containers/DisclosureIndicator.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import { View, StyleSheet } from 'react-native';
-import PropTypes from 'prop-types';
-
-import { themes } from '../constants/colors';
-import { CustomIcon } from '../lib/Icons';
-
-const styles = StyleSheet.create({
- disclosureContainer: {
- marginLeft: 6,
- marginRight: 9,
- alignItems: 'center',
- justifyContent: 'center'
- }
-});
-
-export const DisclosureImage = React.memo(({ theme }) => (
-
-));
-DisclosureImage.propTypes = {
- theme: PropTypes.string
-};
-
-const DisclosureIndicator = React.memo(({ theme }) => (
-
-
-
-));
-DisclosureIndicator.propTypes = {
- theme: PropTypes.string
-};
-
-export default DisclosureIndicator;
diff --git a/app/containers/FormContainer.js b/app/containers/FormContainer.js
index 46a550546..ac58502c7 100644
--- a/app/containers/FormContainer.js
+++ b/app/containers/FormContainer.js
@@ -31,14 +31,14 @@ const FormContainer = ({
contentContainerStyle={sharedStyles.container}
keyboardVerticalOffset={128}
>
-
+
-
+
{children}
diff --git a/app/containers/ItemInfo.js b/app/containers/ItemInfo.js
deleted file mode 100644
index c7d541e64..000000000
--- a/app/containers/ItemInfo.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import { View, Text, StyleSheet } from 'react-native';
-import PropTypes from 'prop-types';
-
-import sharedStyles from '../views/Styles';
-import { themes } from '../constants/colors';
-
-const styles = StyleSheet.create({
- infoContainer: {
- padding: 15
- },
- infoText: {
- fontSize: 14,
- ...sharedStyles.textRegular
- }
-});
-
-const ItemInfo = React.memo(({ info, theme }) => (
-
- {info}
-
-));
-
-ItemInfo.propTypes = {
- info: PropTypes.string,
- theme: PropTypes.string
-};
-
-export default ItemInfo;
diff --git a/app/containers/List/ListContainer.js b/app/containers/List/ListContainer.js
new file mode 100644
index 000000000..f1be3705a
--- /dev/null
+++ b/app/containers/List/ListContainer.js
@@ -0,0 +1,30 @@
+import React from 'react';
+import { ScrollView, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+import { withTheme } from '../../theme';
+import scrollPersistTaps from '../../utils/scrollPersistTaps';
+
+const styles = StyleSheet.create({
+ container: {
+ paddingVertical: 16
+ }
+});
+
+const ListContainer = React.memo(({ children, ...props }) => (
+
+ {children}
+
+));
+
+ListContainer.propTypes = {
+ children: PropTypes.array.isRequired
+};
+
+ListContainer.displayName = 'List.Container';
+
+export default withTheme(ListContainer);
diff --git a/app/containers/List/ListHeader.js b/app/containers/List/ListHeader.js
new file mode 100644
index 000000000..1166e25bd
--- /dev/null
+++ b/app/containers/List/ListHeader.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+
+import sharedStyles from '../../views/Styles';
+import { themes } from '../../constants/colors';
+import I18n from '../../i18n';
+import { withTheme } from '../../theme';
+import { PADDING_HORIZONTAL } from './constants';
+
+const styles = StyleSheet.create({
+ container: {
+ paddingBottom: 12,
+ paddingHorizontal: PADDING_HORIZONTAL
+ },
+ title: {
+ fontSize: 16,
+ ...sharedStyles.textRegular
+ }
+});
+
+const ListHeader = React.memo(({ title, theme, translateTitle }) => (
+
+ {translateTitle ? I18n.t(title) : title}
+
+));
+
+ListHeader.propTypes = {
+ title: PropTypes.string,
+ theme: PropTypes.string,
+ translateTitle: PropTypes.bool
+};
+
+ListHeader.defaultProps = {
+ translateTitle: true
+};
+
+ListHeader.displayName = 'List.Header';
+
+export default withTheme(ListHeader);
diff --git a/app/containers/List/ListIcon.js b/app/containers/List/ListIcon.js
new file mode 100644
index 000000000..1a1b3164c
--- /dev/null
+++ b/app/containers/List/ListIcon.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+
+import { themes } from '../../constants/colors';
+import { CustomIcon } from '../../lib/Icons';
+import { withTheme } from '../../theme';
+
+const styles = StyleSheet.create({
+ icon: {
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+});
+
+const ListIcon = React.memo(({ theme, name, color }) => (
+
+
+
+));
+
+ListIcon.propTypes = {
+ theme: PropTypes.string,
+ name: PropTypes.string,
+ color: PropTypes.string
+};
+
+ListIcon.displayName = 'List.Icon';
+
+export default withTheme(ListIcon);
diff --git a/app/containers/List/ListInfo.js b/app/containers/List/ListInfo.js
new file mode 100644
index 000000000..e0cb9eae7
--- /dev/null
+++ b/app/containers/List/ListInfo.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+
+import sharedStyles from '../../views/Styles';
+import { themes } from '../../constants/colors';
+import { withTheme } from '../../theme';
+import { PADDING_HORIZONTAL } from './constants';
+import I18n from '../../i18n';
+
+const styles = StyleSheet.create({
+ container: {
+ paddingTop: 8,
+ paddingHorizontal: PADDING_HORIZONTAL
+ },
+ text: {
+ fontSize: 14,
+ ...sharedStyles.textRegular
+ }
+});
+
+const ListInfo = React.memo(({ info, translateInfo, theme }) => (
+
+ {translateInfo ? I18n.t(info) : info}
+
+));
+
+ListInfo.propTypes = {
+ info: PropTypes.string,
+ theme: PropTypes.string,
+ translateInfo: PropTypes.bool
+};
+
+ListInfo.defaultProps = {
+ translateInfo: true
+};
+
+ListInfo.displayName = 'List.Info';
+
+export default withTheme(ListInfo);
diff --git a/app/containers/List/ListItem.js b/app/containers/List/ListItem.js
new file mode 100644
index 000000000..0dcf2a6d7
--- /dev/null
+++ b/app/containers/List/ListItem.js
@@ -0,0 +1,137 @@
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+
+import Touch from '../../utils/touch';
+import { themes } from '../../constants/colors';
+import sharedStyles from '../../views/Styles';
+import { withTheme } from '../../theme';
+import I18n from '../../i18n';
+import { Icon } from '.';
+import { BASE_HEIGHT, PADDING_HORIZONTAL } from './constants';
+import { withDimensions } from '../../dimensions';
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingHorizontal: PADDING_HORIZONTAL
+ },
+ leftContainer: {
+ paddingRight: PADDING_HORIZONTAL
+ },
+ rightContainer: {
+ paddingLeft: PADDING_HORIZONTAL
+ },
+ disabled: {
+ opacity: 0.3
+ },
+ textContainer: {
+ flex: 1,
+ justifyContent: 'center'
+ },
+ title: {
+ fontSize: 16,
+ ...sharedStyles.textRegular
+ },
+ subtitle: {
+ fontSize: 14,
+ ...sharedStyles.textRegular
+ }
+});
+
+const Content = React.memo(({
+ title, subtitle, disabled, testID, left, right, color, theme, translateTitle, translateSubtitle, showActionIndicator, fontScale
+}) => (
+
+ {left
+ ? (
+
+ {left()}
+
+ )
+ : null}
+
+ {translateTitle ? I18n.t(title) : title}
+ {subtitle
+ ? {translateSubtitle ? I18n.t(subtitle) : subtitle}
+ : null
+ }
+
+ {right || showActionIndicator
+ ? (
+
+ {right ? right() : null}
+ {showActionIndicator ? : null}
+
+ )
+ : null}
+
+));
+
+const Button = React.memo(({
+ onPress, ...props
+}) => (
+ onPress(props.title)}
+ style={{ backgroundColor: themes[props.theme].backgroundColor }}
+ enabled={!props.disabled}
+ theme={props.theme}
+ >
+
+
+));
+
+const ListItem = React.memo(({ ...props }) => {
+ if (props.onPress) {
+ return ;
+ }
+ return (
+
+
+
+ );
+});
+
+ListItem.propTypes = {
+ onPress: PropTypes.func,
+ theme: PropTypes.string
+};
+
+ListItem.displayName = 'List.Item';
+
+Content.propTypes = {
+ title: PropTypes.string.isRequired,
+ subtitle: PropTypes.string,
+ left: PropTypes.func,
+ right: PropTypes.func,
+ disabled: PropTypes.bool,
+ testID: PropTypes.string,
+ theme: PropTypes.string,
+ color: PropTypes.string,
+ translateTitle: PropTypes.bool,
+ translateSubtitle: PropTypes.bool,
+ showActionIndicator: PropTypes.bool,
+ fontScale: PropTypes.number
+};
+
+Content.defaultProps = {
+ translateTitle: true,
+ translateSubtitle: true,
+ showActionIndicator: false
+};
+
+Button.propTypes = {
+ title: PropTypes.string,
+ onPress: PropTypes.func,
+ disabled: PropTypes.bool,
+ theme: PropTypes.string
+};
+
+Button.defaultProps = {
+ disabled: false
+};
+
+export default withTheme(withDimensions(ListItem));
diff --git a/app/containers/List/ListSection.js b/app/containers/List/ListSection.js
new file mode 100644
index 000000000..8237190e0
--- /dev/null
+++ b/app/containers/List/ListSection.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+import { withTheme } from '../../theme';
+import { Header } from '.';
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: 16
+ }
+});
+
+const ListSection = React.memo(({ children, title, translateTitle }) => (
+
+ {title ? : null}
+ {children}
+
+));
+
+ListSection.propTypes = {
+ children: PropTypes.array.isRequired,
+ title: PropTypes.string,
+ translateTitle: PropTypes.bool
+};
+
+ListSection.displayName = 'List.Section';
+
+export default withTheme(ListSection);
diff --git a/app/containers/Separator.js b/app/containers/List/ListSeparator.js
similarity index 58%
rename from app/containers/Separator.js
rename to app/containers/List/ListSeparator.js
index 674be3cd9..59cd3580c 100644
--- a/app/containers/Separator.js
+++ b/app/containers/List/ListSeparator.js
@@ -2,7 +2,8 @@ import React from 'react';
import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
-import { themes } from '../constants/colors';
+import { themes } from '../../constants/colors';
+import { withTheme } from '../../theme';
const styles = StyleSheet.create({
separator: {
@@ -11,7 +12,7 @@ const styles = StyleSheet.create({
});
-const Separator = React.memo(({ style, theme }) => (
+const ListSeparator = React.memo(({ style, theme }) => (
(
/>
));
-Separator.propTypes = {
+ListSeparator.propTypes = {
style: PropTypes.object,
theme: PropTypes.string
};
-export default Separator;
+ListSeparator.displayName = 'List.Separator';
+
+export default withTheme(ListSeparator);
diff --git a/app/containers/List/constants.js b/app/containers/List/constants.js
new file mode 100644
index 000000000..b69a04f95
--- /dev/null
+++ b/app/containers/List/constants.js
@@ -0,0 +1,2 @@
+export const PADDING_HORIZONTAL = 12;
+export const BASE_HEIGHT = 46;
diff --git a/app/containers/List/index.js b/app/containers/List/index.js
new file mode 100644
index 000000000..6456f5227
--- /dev/null
+++ b/app/containers/List/index.js
@@ -0,0 +1,8 @@
+export { default as Container } from './ListContainer';
+export { default as Item } from './ListItem';
+export { default as Section } from './ListSection';
+export { default as Icon } from './ListIcon';
+export { default as Separator } from './ListSeparator';
+export { default as Header } from './ListHeader';
+export { default as Info } from './ListInfo';
+export * from './styles';
diff --git a/app/containers/List/styles.js b/app/containers/List/styles.js
new file mode 100644
index 000000000..2c0904284
--- /dev/null
+++ b/app/containers/List/styles.js
@@ -0,0 +1,7 @@
+import { StyleSheet } from 'react-native';
+
+export const styles = StyleSheet.create({
+ contentContainerStyleFlatList: {
+ paddingVertical: 32
+ }
+});
diff --git a/app/containers/ListItem.js b/app/containers/ListItem.js
deleted file mode 100644
index 6b7498dd8..000000000
--- a/app/containers/ListItem.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import { View, Text, StyleSheet } from 'react-native';
-import PropTypes from 'prop-types';
-
-import Touch from '../utils/touch';
-import { themes } from '../constants/colors';
-import sharedStyles from '../views/Styles';
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- height: 46,
- paddingHorizontal: 15
- },
- disabled: {
- opacity: 0.3
- },
- textContainer: {
- flex: 1,
- justifyContent: 'center'
- },
- title: {
- fontSize: 16,
- ...sharedStyles.textRegular
- },
- subtitle: {
- fontSize: 14,
- ...sharedStyles.textRegular
- }
-});
-
-const Content = React.memo(({
- title, subtitle, disabled, testID, left, right, color, theme
-}) => (
-
- {left ? left() : null}
-
- {title}
- {subtitle
- ? {subtitle}
- : null
- }
-
- {right ? right() : null}
-
-));
-
-const Button = React.memo(({
- onPress, ...props
-}) => (
- onPress(props.title)}
- style={{ backgroundColor: themes[props.theme].backgroundColor }}
- enabled={!props.disabled}
- theme={props.theme}
- >
-
-
-));
-
-const Item = React.memo(({ ...props }) => {
- if (props.onPress) {
- return ;
- }
- return (
-
-
-
- );
-});
-
-Item.propTypes = {
- onPress: PropTypes.func,
- theme: PropTypes.string
-};
-
-Content.propTypes = {
- title: PropTypes.string.isRequired,
- subtitle: PropTypes.string,
- left: PropTypes.func,
- right: PropTypes.func,
- disabled: PropTypes.bool,
- testID: PropTypes.string,
- theme: PropTypes.string,
- color: PropTypes.string
-};
-
-Button.propTypes = {
- title: PropTypes.string,
- onPress: PropTypes.func,
- disabled: PropTypes.bool,
- theme: PropTypes.string
-};
-
-Button.defaultProps = {
- disabled: false
-};
-
-export default Item;
diff --git a/app/containers/ReactionsModal.js b/app/containers/ReactionsModal.js
index 68e95a33f..5713e0f3a 100644
--- a/app/containers/ReactionsModal.js
+++ b/app/containers/ReactionsModal.js
@@ -99,7 +99,7 @@ const ModalContent = React.memo(({
}) => {
if (message && message.reactions) {
return (
-
+
{
if (!barStyle) {
@@ -20,4 +21,4 @@ StatusBar.propTypes = {
backgroundColor: PropTypes.string
};
-export default StatusBar;
+export default withTheme(StatusBar);
diff --git a/app/containers/UIKit/Divider.js b/app/containers/UIKit/Divider.js
index 736cb9d79..f616f8117 100644
--- a/app/containers/UIKit/Divider.js
+++ b/app/containers/UIKit/Divider.js
@@ -1,8 +1,7 @@
import React from 'react';
import { StyleSheet } from 'react-native';
-import PropTypes from 'prop-types';
-import Separator from '../Separator';
+import * as List from '../List';
const styles = StyleSheet.create({
separator: {
@@ -12,7 +11,4 @@ const styles = StyleSheet.create({
}
});
-export const Divider = ({ theme }) => ;
-Divider.propTypes = {
- theme: PropTypes.string
-};
+export const Divider = () => ;
diff --git a/app/containers/UIKit/MultiSelect/Items.js b/app/containers/UIKit/MultiSelect/Items.js
index 4418600f5..c1619e2e2 100644
--- a/app/containers/UIKit/MultiSelect/Items.js
+++ b/app/containers/UIKit/MultiSelect/Items.js
@@ -4,9 +4,8 @@ import PropTypes from 'prop-types';
import Touchable from 'react-native-platform-touchable';
import FastImage from '@rocket.chat/react-native-fast-image';
-import Separator from '../../Separator';
import Check from '../../Check';
-
+import * as List from '../../List';
import { textParser } from '../utils';
import { themes } from '../../../constants/colors';
@@ -48,7 +47,7 @@ const Items = ({
style={[styles.items, { backgroundColor: themes[theme].backgroundColor }]}
contentContainerStyle={[styles.itemContent, { backgroundColor: themes[theme].backgroundColor }]}
keyboardShouldPersistTaps='always'
- ItemSeparatorComponent={() => }
+ ItemSeparatorComponent={List.Separator}
keyExtractor={keyExtractor}
renderItem={({ item }) => - s === item.value)} />}
/>
diff --git a/app/containers/UIKit/Overflow.js b/app/containers/UIKit/Overflow.js
index 5acc4e9fe..73104e172 100644
--- a/app/containers/UIKit/Overflow.js
+++ b/app/containers/UIKit/Overflow.js
@@ -5,10 +5,10 @@ import Popover from 'react-native-popover-view';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../lib/Icons';
-import Separator from '../Separator';
import ActivityIndicator from '../ActivityIndicator';
import { themes } from '../../constants/colors';
import { BUTTON_HIT_SLOP } from '../message/utils';
+import * as List from '../List';
const keyExtractor = item => item.value;
@@ -50,7 +50,7 @@ const Options = ({
data={options}
renderItem={({ item }) => }
keyExtractor={keyExtractor}
- ItemSeparatorComponent={() => }
+ ItemSeparatorComponent={List.Separator}
/>
);
Options.propTypes = {
diff --git a/app/containers/message/RepliedThread.js b/app/containers/message/RepliedThread.js
index 7d02d7494..d51ff7bc2 100644
--- a/app/containers/message/RepliedThread.js
+++ b/app/containers/message/RepliedThread.js
@@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import { CustomIcon } from '../../lib/Icons';
-import DisclosureIndicator from '../DisclosureIndicator';
import styles from './styles';
import { themes } from '../../constants/colors';
import I18n from '../../i18n';
@@ -33,7 +32,13 @@ const RepliedThread = React.memo(({
{msg}
-
+
+
+
);
}, (prevProps, nextProps) => {
diff --git a/app/containers/message/styles.js b/app/containers/message/styles.js
index f83c64f0c..ef51afa77 100644
--- a/app/containers/message/styles.js
+++ b/app/containers/message/styles.js
@@ -164,6 +164,12 @@ export default StyleSheet.create({
flex: 1,
...sharedStyles.textRegular
},
+ repliedThreadDisclosure: {
+ marginLeft: 4,
+ marginRight: 4,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
readReceipt: {
lineHeight: 20
},
diff --git a/app/ee/omnichannel/views/QueueListView.js b/app/ee/omnichannel/views/QueueListView.js
index 67ee16009..d365db6cb 100644
--- a/app/ee/omnichannel/views/QueueListView.js
+++ b/app/ee/omnichannel/views/QueueListView.js
@@ -128,8 +128,8 @@ class QueueListView extends React.Component {
render() {
const { queued, theme } = this.props;
return (
-
-
+
+
{
- this.setDimensions({ width, height, scale });
+ onDimensionsChange = debounce(({
+ window: {
+ width, height, scale, fontScale
+ }
+ }) => {
+ this.setDimensions({
+ width, height, scale, fontScale
+ });
this.setMasterDetail(width);
})
@@ -148,8 +157,12 @@ export default class Root extends React.Component {
});
}
- setDimensions = ({ width, height, scale }) => {
- this.setState({ width, height, scale });
+ setDimensions = ({
+ width, height, scale, fontScale
+ }) => {
+ this.setState({
+ width, height, scale, fontScale
+ });
}
initTablet = () => {
@@ -176,7 +189,7 @@ export default class Root extends React.Component {
render() {
const {
- themePreferences, theme, width, height, scale
+ themePreferences, theme, width, height, scale, fontScale
} = this.state;
return (
@@ -194,6 +207,7 @@ export default class Root extends React.Component {
width,
height,
scale,
+ fontScale,
setDimensions: this.setDimensions
}}
>
diff --git a/app/share.js b/app/share.js
index d1f83fd88..1edbfa5c4 100644
--- a/app/share.js
+++ b/app/share.js
@@ -117,7 +117,9 @@ App.propTypes = {
class Root extends React.Component {
constructor(props) {
super(props);
- const { width, height, scale } = Dimensions.get('screen');
+ const {
+ width, height, scale, fontScale
+ } = Dimensions.get('screen');
this.state = {
theme: defaultTheme(),
themePreferences: {
@@ -127,7 +129,8 @@ class Root extends React.Component {
root: '',
width,
height,
- scale
+ scale,
+ fontScale
};
this.init();
}
@@ -166,18 +169,28 @@ class Root extends React.Component {
}
// Dimensions update fires twice
- onDimensionsChange = debounce(({ window: { width, height, scale } }) => {
- this.setDimensions({ width, height, scale });
+ onDimensionsChange = debounce(({
+ window: {
+ width, height, scale, fontScale
+ }
+ }) => {
+ this.setDimensions({
+ width, height, scale, fontScale
+ });
this.setMasterDetail(width);
})
- setDimensions = ({ width, height, scale }) => {
- this.setState({ width, height, scale });
+ setDimensions = ({
+ width, height, scale, fontScale
+ }) => {
+ this.setState({
+ width, height, scale, fontScale
+ });
}
render() {
const {
- theme, root, width, height, scale
+ theme, root, width, height, scale, fontScale
} = this.state;
const navTheme = navigationTheme(theme);
return (
@@ -189,6 +202,7 @@ class Root extends React.Component {
width,
height,
scale,
+ fontScale,
setDimensions: this.setDimensions
}}
>
diff --git a/app/views/AdminPanelView/index.js b/app/views/AdminPanelView/index.js
index 41005fc93..814c8c76e 100644
--- a/app/views/AdminPanelView/index.js
+++ b/app/views/AdminPanelView/index.js
@@ -18,18 +18,17 @@ class AdminPanelView extends React.Component {
static propTypes = {
baseUrl: PropTypes.string,
- token: PropTypes.string,
- theme: PropTypes.string
+ token: PropTypes.string
}
render() {
- const { baseUrl, token, theme } = this.props;
+ const { baseUrl, token } = this.props;
if (!baseUrl) {
return null;
}
return (
-
-
+
+
{}}
diff --git a/app/views/AuthLoadingView.js b/app/views/AuthLoadingView.js
index 6769af899..b0ecf2474 100644
--- a/app/views/AuthLoadingView.js
+++ b/app/views/AuthLoadingView.js
@@ -28,7 +28,7 @@ const styles = StyleSheet.create({
const AuthLoadingView = React.memo(({ theme, text }) => (
-
+
{text && (
<>
diff --git a/app/views/AuthenticationWebView.js b/app/views/AuthenticationWebView.js
index 2eca58eda..1b51b64ba 100644
--- a/app/views/AuthenticationWebView.js
+++ b/app/views/AuthenticationWebView.js
@@ -155,7 +155,7 @@ class AuthenticationWebView extends React.PureComponent {
return (
<>
-
+
(
-
-));
-
-SectionSeparator.propTypes = {
- theme: PropTypes.string
-};
-
class AutoTranslateView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Auto_Translate')
@@ -55,8 +24,7 @@ class AutoTranslateView extends React.Component {
static propTypes = {
route: PropTypes.object,
- theme: PropTypes.string,
- navigation: PropTypes.object
+ theme: PropTypes.string
}
constructor(props) {
@@ -135,14 +103,9 @@ class AutoTranslateView extends React.Component {
}
}
- renderSeparator = () => {
- const { theme } = this.props;
- return ;
- }
-
renderIcon = () => {
const { theme } = this.props;
- return ;
+ return ;
}
renderSwitch = () => {
@@ -158,54 +121,46 @@ class AutoTranslateView extends React.Component {
renderItem = ({ item }) => {
const { selectedLanguage } = this.state;
- const { theme } = this.props;
const { language, name } = item;
const isSelected = selectedLanguage === language;
return (
- this.saveAutoTranslateLanguage(language)}
testID={`auto-translate-view-${ language }`}
right={isSelected ? this.renderIcon : null}
- theme={theme}
+ translateTitle={false}
/>
);
}
render() {
const { languages } = this.state;
- const { theme } = this.props;
return (
-
-
-
- this.renderSwitch()}
- theme={theme}
- />
-
+
+
+
+
+
+ this.renderSwitch()}
+ />
+
+
item.language}
renderItem={this.renderItem}
- ItemSeparatorComponent={this.renderSeparator}
- contentContainerStyle={[styles.flatListContainerStyle, { borderColor: themes[theme].separatorColor }]}
+ ItemSeparatorComponent={List.Separator}
+ ListFooterComponent={List.Separator}
+ ListHeaderComponent={List.Separator}
+ contentContainerStyle={[List.styles.contentContainerStyleFlatList, styles.list]}
/>
-
+
);
}
diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js
index c78be31dd..8d03d21e5 100644
--- a/app/views/CreateChannelView.js
+++ b/app/views/CreateChannelView.js
@@ -323,8 +323,8 @@ class CreateChannelView extends React.Component {
contentContainerStyle={[sharedStyles.container, styles.container]}
keyboardVerticalOffset={128}
>
-
-
+
+
-
-
+
+
{I18n.t('Discussion_Desc')}
({
title: I18n.t('Default_browser')
@@ -120,59 +100,44 @@ class DefaultBrowserView extends React.Component {
}
}
- renderSeparator = () => {
- const { theme } = this.props;
- return ;
- }
-
renderIcon = () => {
const { theme } = this.props;
- return ;
+ return ;
}
renderItem = ({ item }) => {
- const { theme } = this.props;
const { title, value } = item;
return (
- this.changeDefaultBrowser(value)}
testID={`default-browser-view-${ title }`}
right={this.isSelected(value) ? this.renderIcon : null}
- theme={theme}
+ translateTitle={false}
/>
);
}
- renderHeader = () => {
- const { theme } = this.props;
- return (
- <>
-
- {I18n.t('Choose_where_you_want_links_be_opened')}
-
- {this.renderSeparator()}
- >
- );
- }
+ renderHeader = () => (
+ <>
+
+
+ >
+ )
render() {
const { supported } = this.state;
- const { theme } = this.props;
return (
-
-
+
+
item.value}
- contentContainerStyle={[
- styles.list,
- { borderColor: themes[theme].separatorColor }
- ]}
+ contentContainerStyle={List.styles.contentContainerStyleFlatList}
renderItem={this.renderItem}
ListHeaderComponent={this.renderHeader}
- ListFooterComponent={this.renderSeparator}
- ItemSeparatorComponent={this.renderSeparator}
+ ListFooterComponent={List.Separator}
+ ItemSeparatorComponent={List.Separator}
/>
);
diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js
index e21d2e9d1..9b89c8225 100644
--- a/app/views/DirectoryView/index.js
+++ b/app/views/DirectoryView/index.js
@@ -240,9 +240,8 @@ class DirectoryView extends React.Component {
-
+
-
+
-
+
{ this.passwordInput = e; }}
placeholder={I18n.t('Password')}
diff --git a/app/views/E2EHowItWorksView.js b/app/views/E2EHowItWorksView.js
index 97dc71b5e..dcaf5f736 100644
--- a/app/views/E2EHowItWorksView.js
+++ b/app/views/E2EHowItWorksView.js
@@ -43,7 +43,6 @@ class E2EHowItWorksView extends React.Component {
-
+
+
{I18n.t('Save_Your_Encryption_Password_warning')}
diff --git a/app/views/InviteUsersEditView/index.js b/app/views/InviteUsersEditView/index.js
index d5f8d6fb4..bba6ef247 100644
--- a/app/views/InviteUsersEditView/index.js
+++ b/app/views/InviteUsersEditView/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { ScrollView, View } from 'react-native';
+import { View } from 'react-native';
import { connect } from 'react-redux';
import RNPickerSelect from 'react-native-picker-select';
@@ -8,15 +8,13 @@ import {
inviteLinksSetParams as inviteLinksSetParamsAction,
inviteLinksCreate as inviteLinksCreateAction
} from '../../actions/inviteLinks';
-import ListItem from '../../containers/ListItem';
+import * as List from '../../containers/List';
import styles from './styles';
import Button from '../../containers/Button';
-import scrollPersistTaps from '../../utils/scrollPersistTaps';
import I18n from '../../i18n';
import StatusBar from '../../containers/StatusBar';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
-import Separator from '../../containers/Separator';
import SafeAreaView from '../../containers/SafeAreaView';
import { logEvent, events } from '../../utils/log';
@@ -62,7 +60,6 @@ class InviteUsersView extends React.Component {
navigation: PropTypes.object,
route: PropTypes.object,
theme: PropTypes.string,
- timeDateFormat: PropTypes.string,
createInviteLink: PropTypes.func,
inviteLinksSetParams: PropTypes.func
}
@@ -110,29 +107,23 @@ class InviteUsersView extends React.Component {
render() {
const { theme } = this.props;
return (
-
-
-
-
- this.renderPicker('days', 'Never')}
- theme={theme}
- />
-
- this.renderPicker('maxUses', 'No_limit')}
- theme={theme}
- />
-
+
+
+
+
+
+ this.renderPicker('days', 'Never')}
+ />
+
+ this.renderPicker('maxUses', 'No_limit')}
+ />
+
+
-
-
+
);
}
diff --git a/app/views/InviteUsersEditView/styles.js b/app/views/InviteUsersEditView/styles.js
index 1e4bf8e32..bb2950300 100644
--- a/app/views/InviteUsersEditView/styles.js
+++ b/app/views/InviteUsersEditView/styles.js
@@ -1,36 +1,12 @@
import { StyleSheet } from 'react-native';
+import { PADDING_HORIZONTAL } from '../../containers/List/constants';
import sharedStyles from '../Styles';
export default StyleSheet.create({
innerContainer: {
- paddingHorizontal: 20
- },
- divider: {
- width: '100%',
- height: StyleSheet.hairlineWidth,
- marginVertical: 20
- },
- sectionSeparatorBorder: {
- height: 10
- },
- marginBottom: {
- height: 30
- },
- contentContainer: {
- marginVertical: 10
- },
- infoText: {
- ...sharedStyles.textRegular,
- fontSize: 13,
- paddingHorizontal: 15,
- paddingVertical: 10
- },
- sectionTitle: {
- ...sharedStyles.separatorBottom,
- paddingHorizontal: 15,
- paddingVertical: 10,
- fontSize: 14
+ paddingHorizontal: PADDING_HORIZONTAL,
+ paddingTop: 16
},
viewContainer: {
justifyContent: 'center'
diff --git a/app/views/InviteUsersView/index.js b/app/views/InviteUsersView/index.js
index 875594b12..c6be109a9 100644
--- a/app/views/InviteUsersView/index.js
+++ b/app/views/InviteUsersView/index.js
@@ -102,14 +102,14 @@ class InviteUsersView extends React.Component {
theme, invite
} = this.props;
return (
-
+
-
+
{
- const { theme } = this.props;
- return ;
- }
-
renderIcon = () => {
const { theme } = this.props;
- return ;
+ return ;
}
renderItem = ({ item }) => {
const { value, label } = item;
const { language } = this.state;
- const { theme } = this.props;
const isSelected = language === value;
return (
- this.submit(value)}
testID={`language-view-${ value }`}
right={isSelected ? this.renderIcon : null}
- theme={theme}
+ translateTitle={false}
/>
);
}
render() {
- const { theme } = this.props;
return (
-
-
+
+
item.value}
- contentContainerStyle={[
- sharedStyles.listContentContainer,
- {
- backgroundColor: themes[theme].auxiliaryBackground,
- borderColor: themes[theme].separatorColor
- }
- ]}
+ ListHeaderComponent={List.Separator}
+ ListFooterComponent={List.Separator}
+ contentContainerStyle={List.styles.contentContainerStyleFlatList}
renderItem={this.renderItem}
- ItemSeparatorComponent={this.renderSeparator}
+ ItemSeparatorComponent={List.Separator}
/>
);
diff --git a/app/views/LegalView.js b/app/views/LegalView.js
index 822b7fc18..e8d61fda0 100644
--- a/app/views/LegalView.js
+++ b/app/views/LegalView.js
@@ -1,51 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {
- Text, ScrollView, View, StyleSheet
-} from 'react-native';
import { connect } from 'react-redux';
-import Touch from '../utils/touch';
-import sharedStyles from './Styles';
-import scrollPersistTaps from '../utils/scrollPersistTaps';
import I18n from '../i18n';
-import DisclosureIndicator from '../containers/DisclosureIndicator';
import StatusBar from '../containers/StatusBar';
-import { themes } from '../constants/colors';
import openLink from '../utils/openLink';
import { withTheme } from '../theme';
import SafeAreaView from '../containers/SafeAreaView';
-
-const styles = StyleSheet.create({
- scroll: {
- marginTop: 35,
- borderTopWidth: StyleSheet.hairlineWidth,
- borderBottomWidth: StyleSheet.hairlineWidth
- },
- separator: {
- height: StyleSheet.hairlineWidth,
- width: '100%',
- marginLeft: 20
- },
- item: {
- width: '100%',
- height: 48,
- paddingLeft: 20,
- paddingRight: 10,
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between'
- },
- text: {
- ...sharedStyles.textMedium,
- fontSize: 18
- }
-});
-
-const Separator = ({ theme }) => ;
-Separator.propTypes = {
- theme: PropTypes.string
-};
+import * as List from '../containers/List';
class LegalView extends React.Component {
static propTypes = {
@@ -61,40 +23,29 @@ class LegalView extends React.Component {
openLink(`${ server }/${ route }`, theme);
}
- renderItem = ({ text, route, testID }) => {
- const { theme } = this.props;
- return (
- this.onPressItem({ route })}
- testID={testID}
- theme={theme}
- >
- {I18n.t(text)}
-
-
- );
- }
-
render() {
- const { theme } = this.props;
return (
-
-
-
- {this.renderItem({ text: 'Terms_of_Service', route: 'terms-of-service', testID: 'legal-terms-button' })}
-
- {this.renderItem({ text: 'Privacy_Policy', route: 'privacy-policy', testID: 'legal-privacy-button' })}
-
+
+
+
+
+
+ this.onPressItem({ route: 'terms-of-service' })}
+ testID='legal-terms-button'
+ showActionIndicator
+ />
+
+ this.onPressItem({ route: 'privacy-policy' })}
+ testID='legal-privacy-button'
+ showActionIndicator
+ />
+
+
+
);
}
diff --git a/app/views/LivechatEditView.js b/app/views/LivechatEditView.js
index 332eb3ca7..6ba4143e7 100644
--- a/app/views/LivechatEditView.js
+++ b/app/views/LivechatEditView.js
@@ -151,7 +151,7 @@ const LivechatEditView = ({
keyboardVerticalOffset={128}
>
-
+
-
+
{
- const { theme } = this.props;
+ render() {
return (
-
-
+
+
{this.renderList()}
);
diff --git a/app/views/NewServerView/ServerInput/index.js b/app/views/NewServerView/ServerInput/index.js
index 73e85b910..4f13f8894 100644
--- a/app/views/NewServerView/ServerInput/index.js
+++ b/app/views/NewServerView/ServerInput/index.js
@@ -3,9 +3,9 @@ import { View, FlatList, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import TextInput from '../../../containers/TextInput';
+import * as List from '../../../containers/List';
import { themes } from '../../../constants/colors';
import Item from './Item';
-import Separator from '../../../containers/Separator';
const styles = StyleSheet.create({
container: {
@@ -64,7 +64,7 @@ const ServerInput = ({
- onPressServerHistory(item)} onDelete={onDelete} />}
- ItemSeparatorComponent={() => }
+ ItemSeparatorComponent={List.Separator}
keyExtractor={item => item.id}
/>
diff --git a/app/views/NotificationPreferencesView/Info.js b/app/views/NotificationPreferencesView/Info.js
deleted file mode 100644
index 0c01e3c16..000000000
--- a/app/views/NotificationPreferencesView/Info.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import {
- Text
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-import styles from './styles';
-import { themes } from '../../constants/colors';
-
-const Info = React.memo(({ info, theme }) => (
-
- {info}
-
-));
-
-Info.propTypes = {
- info: PropTypes.string,
- theme: PropTypes.string
-};
-
-export default Info;
diff --git a/app/views/NotificationPreferencesView/SectionSeparator.js b/app/views/NotificationPreferencesView/SectionSeparator.js
deleted file mode 100644
index 88acd1a0e..000000000
--- a/app/views/NotificationPreferencesView/SectionSeparator.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import {
- View
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-import styles from './styles';
-import { themes } from '../../constants/colors';
-
-const SectionSeparator = React.memo(({ theme }) => (
-
-));
-
-SectionSeparator.propTypes = {
- theme: PropTypes.string
-};
-
-export default SectionSeparator;
diff --git a/app/views/NotificationPreferencesView/SectionTitle.js b/app/views/NotificationPreferencesView/SectionTitle.js
deleted file mode 100644
index e93cb0e01..000000000
--- a/app/views/NotificationPreferencesView/SectionTitle.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import {
- Text
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-import styles from './styles';
-import { themes } from '../../constants/colors';
-
-const SectionTitle = React.memo(({ title, theme }) => (
-
- {title}
-
-));
-
-SectionTitle.propTypes = {
- title: PropTypes.string,
- theme: PropTypes.string
-};
-
-export default SectionTitle;
diff --git a/app/views/NotificationPreferencesView/index.js b/app/views/NotificationPreferencesView/index.js
index 1cbc23db3..debea1492 100644
--- a/app/views/NotificationPreferencesView/index.js
+++ b/app/views/NotificationPreferencesView/index.js
@@ -1,26 +1,26 @@
import React from 'react';
-import {
- View, ScrollView, Switch, Text
-} from 'react-native';
+import { Switch, Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import database from '../../lib/database';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
import StatusBar from '../../containers/StatusBar';
-import ListItem from '../../containers/ListItem';
-import Separator from '../../containers/Separator';
+import * as List from '../../containers/List';
import I18n from '../../i18n';
-import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import styles from './styles';
import RocketChat from '../../lib/rocketchat';
import { withTheme } from '../../theme';
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import SafeAreaView from '../../containers/SafeAreaView';
import log, { events, logEvent } from '../../utils/log';
-import SectionTitle from './SectionTitle';
-import SectionSeparator from './SectionSeparator';
-import Info from './Info';
import { OPTIONS } from './options';
+import sharedStyles from '../Styles';
+
+const styles = StyleSheet.create({
+ pickerText: {
+ ...sharedStyles.textRegular,
+ fontSize: 16
+ }
+});
class NotificationPreferencesView extends React.Component {
static navigationOptions = () => ({
@@ -132,120 +132,103 @@ class NotificationPreferencesView extends React.Component {
render() {
const { room } = this.state;
- const { theme } = this.props;
return (
-
-
-
-
- this.renderSwitch('disableNotifications')}
- theme={theme}
- />
-
-
-
+
+
+
+
+
+ this.renderSwitch('disableNotifications')}
+ />
+
+
+
-
- this.renderSwitch('muteGroupMentions')}
- theme={theme}
- />
-
-
+
+
+ this.renderSwitch('muteGroupMentions')}
+ />
+
+
+
-
-
- this.renderSwitch('hideUnreadStatus')}
- theme={theme}
- />
-
-
+
+
+ this.renderSwitch('hideUnreadStatus')}
+ />
+
+
+
-
-
-
+
+
+ this.pickerSelection(title, 'desktopNotifications')}
+ right={() => this.renderPickerOption('desktopNotifications')}
+ />
+
+
+
- this.pickerSelection(title, 'desktopNotifications')}
- right={() => this.renderPickerOption('desktopNotifications')}
- theme={theme}
- />
-
-
+
+
+ this.pickerSelection(title, 'mobilePushNotifications')}
+ right={() => this.renderPickerOption('mobilePushNotifications')}
+ />
+
+
+
-
-
-
+
+
+ this.pickerSelection(title, 'audioNotifications')}
+ right={() => this.renderPickerOption('audioNotifications')}
+ />
+
+ this.pickerSelection(title, 'audioNotificationValue')}
+ right={() => this.renderPickerOption('audioNotificationValue')}
+ />
+
+ this.pickerSelection(title, 'desktopNotificationDuration')}
+ right={() => this.renderPickerOption('desktopNotificationDuration')}
+ />
+
+
- this.pickerSelection(title, 'mobilePushNotifications')}
- right={() => this.renderPickerOption('mobilePushNotifications')}
- theme={theme}
- />
-
-
-
-
-
-
-
- this.pickerSelection(title, 'audioNotifications')}
- right={() => this.renderPickerOption('audioNotifications')}
- theme={theme}
- />
-
- this.pickerSelection(title, 'audioNotificationValue')}
- right={() => this.renderPickerOption('audioNotificationValue')}
- theme={theme}
- />
-
- this.pickerSelection(title, 'desktopNotificationDuration')}
- right={() => this.renderPickerOption('desktopNotificationDuration')}
- theme={theme}
- />
-
-
-
-
-
-
- this.pickerSelection(title, 'emailNotifications')}
- right={() => this.renderPickerOption('emailNotifications')}
- theme={theme}
- />
-
-
-
-
+
+
+ this.pickerSelection(title, 'emailNotifications')}
+ right={() => this.renderPickerOption('emailNotifications')}
+ />
+
+
+
);
}
diff --git a/app/views/NotificationPreferencesView/styles.js b/app/views/NotificationPreferencesView/styles.js
deleted file mode 100644
index 9b4c9e0e6..000000000
--- a/app/views/NotificationPreferencesView/styles.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { StyleSheet } from 'react-native';
-
-import sharedStyles from '../Styles';
-
-export default StyleSheet.create({
- sectionSeparatorBorder: {
- height: 10
- },
- marginBottom: {
- height: 30
- },
- contentContainer: {
- marginVertical: 10
- },
- infoText: {
- ...sharedStyles.textRegular,
- fontSize: 13,
- paddingHorizontal: 15,
- paddingVertical: 10
- },
- sectionTitle: {
- ...sharedStyles.separatorBottom,
- paddingHorizontal: 15,
- paddingVertical: 10,
- fontSize: 14
- },
- pickerText: {
- ...sharedStyles.textRegular,
- fontSize: 16
- }
-});
diff --git a/app/views/PickerView.js b/app/views/PickerView.js
index 062e373ab..cf1282197 100644
--- a/app/views/PickerView.js
+++ b/app/views/PickerView.js
@@ -10,15 +10,11 @@ import { themes } from '../constants/colors';
import debounce from '../utils/debounce';
import sharedStyles from './Styles';
-import ListItem from '../containers/ListItem';
-import Check from '../containers/Check';
-import Separator from '../containers/Separator';
+import * as List from '../containers/List';
import SearchBox from '../containers/SearchBox';
+import SafeAreaView from '../containers/SafeAreaView';
const styles = StyleSheet.create({
- check: {
- marginHorizontal: 0
- },
search: {
width: '100%',
height: 56
@@ -28,10 +24,6 @@ const styles = StyleSheet.create({
paddingVertical: 56,
...sharedStyles.textAlignCenter,
...sharedStyles.textSemibold
- },
- withoutBorder: {
- borderBottomWidth: 0,
- borderTopWidth: 0
}
});
@@ -41,11 +33,11 @@ const Item = React.memo(({
onItemPress,
theme
}) => (
- )}
+ right={selected && (() => )}
onPress={onItemPress}
- theme={theme}
+ translateTitle={false}
/>
));
Item.propTypes = {
@@ -109,7 +101,7 @@ class PickerView extends React.PureComponent {
const { theme } = this.props;
return (
- <>
+
{this.renderSearch()}
this.onChangeValue(item.value)}
/>
)}
- ItemSeparatorComponent={() => }
+ ItemSeparatorComponent={List.Separator}
+ ListHeaderComponent={List.Separator}
+ ListFooterComponent={List.Separator}
ListEmptyComponent={() => {I18n.t('No_results_found')}}
- contentContainerStyle={[
- sharedStyles.listContentContainer,
- {
- backgroundColor: themes[theme].auxiliaryBackground,
- borderColor: themes[theme].separatorColor
- },
- !data.length && styles.withoutBorder
- ]}
- style={{ backgroundColor: themes[theme].auxiliaryBackground }}
+ contentContainerStyle={[List.styles.contentContainerStyleFlatList]}
/>
- >
+
);
}
}
diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js
index d0842beae..9cd0be097 100644
--- a/app/views/ProfileView/index.js
+++ b/app/views/ProfileView/index.js
@@ -469,8 +469,8 @@ class ProfileView extends React.Component {
contentContainerStyle={sharedStyles.container}
keyboardVerticalOffset={128}
>
-
-
+
+
-
+
+
{loading
?
: (
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index 70dce573c..ba007818d 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
- View, SectionList, Text, Alert, Share, Switch
+ View, Text, Alert, Share, Switch
} from 'react-native';
import { connect } from 'react-redux';
import _ from 'lodash';
@@ -13,24 +13,22 @@ import styles from './styles';
import sharedStyles from '../Styles';
import Avatar from '../../containers/Avatar';
import Status from '../../containers/Status';
+import * as List from '../../containers/List';
import RocketChat from '../../lib/rocketchat';
import log, { logEvent, events } from '../../utils/log';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
-import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import { CustomIcon } from '../../lib/Icons';
-import DisclosureIndicator from '../../containers/DisclosureIndicator';
import StatusBar from '../../containers/StatusBar';
import { themes, SWITCH_TRACK_COLOR } from '../../constants/colors';
import { withTheme } from '../../theme';
import { CloseModalButton } from '../../containers/HeaderButton';
-import { getUserSelector } from '../../selectors/login';
import Markdown from '../../containers/markdown';
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
import SafeAreaView from '../../containers/SafeAreaView';
import { E2E_ROOM_TYPES } from '../../lib/encryption/constants';
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import database from '../../lib/database';
+import { withDimensions } from '../../dimensions';
class RoomActionsView extends React.Component {
static navigationOptions = ({ navigation, isMasterDetail }) => {
@@ -44,19 +42,15 @@ class RoomActionsView extends React.Component {
}
static propTypes = {
- baseUrl: PropTypes.string,
navigation: PropTypes.object,
route: PropTypes.object,
- user: PropTypes.shape({
- id: PropTypes.string,
- token: PropTypes.string
- }),
leaveRoom: PropTypes.func,
jitsiEnabled: PropTypes.bool,
e2eEnabled: PropTypes.bool,
setLoadingInvite: PropTypes.func,
closeRoom: PropTypes.func,
- theme: PropTypes.string
+ theme: PropTypes.string,
+ fontScale: PropTypes.number
}
constructor(props) {
@@ -240,281 +234,6 @@ class RoomActionsView extends React.Component {
}
}
- get sections() {
- const {
- room, member, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate, canForwardGuest, canReturnQueue, canEdit
- } = this.state;
- const { jitsiEnabled, e2eEnabled } = this.props;
- const {
- rid, t, blocker, encrypted
- } = room;
- const isGroupChat = RocketChat.isGroupChat(room);
-
- const notificationsAction = {
- icon: 'notification',
- name: I18n.t('Notifications'),
- route: 'NotificationPrefView',
- params: { rid, room },
- testID: 'room-actions-notifications',
- right: this.renderDisclosure
- };
-
- const jitsiActions = jitsiEnabled ? [
- {
- icon: 'phone',
- name: I18n.t('Voice_call'),
- event: () => RocketChat.callJitsi(rid, true),
- testID: 'room-actions-voice',
- right: this.renderDisclosure
- },
- {
- icon: 'camera',
- name: I18n.t('Video_call'),
- event: () => RocketChat.callJitsi(rid),
- testID: 'room-actions-video',
- right: this.renderDisclosure
- }
- ] : [];
-
- const sections = [{
- data: [{
- icon: 'star',
- name: I18n.t('Room_Info'),
- route: 'RoomInfoView',
- // forward room only if room isn't joined
- params: {
- rid, t, room, member
- },
- disabled: isGroupChat,
- testID: 'room-actions-info'
- }],
- renderItem: this.renderRoomInfo
- }, {
- data: jitsiActions,
- renderItem: this.renderItem
- }, {
- data: [
- {
- icon: 'attach',
- name: I18n.t('Files'),
- route: 'MessagesView',
- params: { rid, t, name: 'Files' },
- testID: 'room-actions-files',
- right: this.renderDisclosure
- },
- {
- icon: 'mention',
- name: I18n.t('Mentions'),
- route: 'MessagesView',
- params: { rid, t, name: 'Mentions' },
- testID: 'room-actions-mentioned',
- right: this.renderDisclosure
- },
- {
- icon: 'star',
- name: I18n.t('Starred'),
- route: 'MessagesView',
- params: { rid, t, name: 'Starred' },
- testID: 'room-actions-starred',
- right: this.renderDisclosure
- },
- {
- icon: 'search',
- name: I18n.t('Search'),
- route: 'SearchMessagesView',
- params: { rid, encrypted },
- testID: 'room-actions-search',
- right: this.renderDisclosure
- },
- {
- icon: 'share',
- name: I18n.t('Share'),
- event: this.handleShare,
- testID: 'room-actions-share',
- right: this.renderDisclosure
- },
- {
- icon: 'pin',
- name: I18n.t('Pinned'),
- route: 'MessagesView',
- params: { rid, t, name: 'Pinned' },
- testID: 'room-actions-pinned',
- right: this.renderDisclosure
- }
- ],
- renderItem: this.renderItem
- }];
-
- if (canAutoTranslate) {
- sections[2].data.push({
- icon: 'language',
- name: I18n.t('Auto_Translate'),
- route: 'AutoTranslateView',
- params: { rid, room },
- testID: 'room-actions-auto-translate',
- right: this.renderDisclosure
- });
- }
-
- if (isGroupChat) {
- sections[2].data.unshift({
- icon: 'team',
- name: I18n.t('Members'),
- description: membersCount > 0 ? `${ membersCount } ${ I18n.t('members') }` : null,
- route: 'RoomMembersView',
- params: { rid, room },
- testID: 'room-actions-members',
- right: this.renderDisclosure
- });
- }
-
- if (t === 'd' && !isGroupChat) {
- sections.push({
- data: [
- {
- icon: 'ban',
- name: I18n.t(`${ blocker ? 'Unblock' : 'Block' }_user`),
- type: 'danger',
- event: this.toggleBlockUser,
- testID: 'room-actions-block-user',
- right: this.renderDisclosure
- }
- ],
- renderItem: this.renderItem
- });
- sections[2].data.push(notificationsAction);
- } else if (t === 'c' || t === 'p') {
- const actions = [];
-
- if (canViewMembers) {
- actions.push({
- icon: 'team',
- name: I18n.t('Members'),
- description: membersCount > 0 ? `${ membersCount } ${ I18n.t('members') }` : null,
- route: 'RoomMembersView',
- params: { rid, room },
- testID: 'room-actions-members',
- right: this.renderDisclosure
- });
- }
-
- if (canAddUser) {
- actions.push({
- icon: 'add',
- name: I18n.t('Add_users'),
- route: 'SelectedUsersView',
- params: {
- rid,
- title: I18n.t('Add_users'),
- nextAction: this.addUser
- },
- testID: 'room-actions-add-user',
- right: this.renderDisclosure
- });
- }
- if (canInviteUser) {
- actions.push({
- icon: 'user-add',
- name: I18n.t('Invite_users'),
- route: 'InviteUsersView',
- params: {
- rid
- },
- testID: 'room-actions-invite-user',
- right: this.renderDisclosure
- });
- }
- sections[2].data = [...actions, ...sections[2].data];
-
- if (joined) {
- sections[2].data.push(notificationsAction);
- sections.push({
- data: [
- {
- icon: 'logout',
- name: I18n.t('Leave_channel'),
- type: 'danger',
- event: this.leaveChannel,
- testID: 'room-actions-leave-channel',
- right: this.renderDisclosure
- }
- ],
- renderItem: this.renderItem
- });
- }
- } else if (t === 'l') {
- sections[2].data = [];
-
- if (!this.isOmnichannelPreview) {
- sections[2].data.push({
- icon: 'close',
- name: I18n.t('Close'),
- event: this.closeLivechat,
- right: this.renderDisclosure
- });
-
- if (canForwardGuest) {
- sections[2].data.push({
- icon: 'user-forward',
- name: I18n.t('Forward'),
- route: 'ForwardLivechatView',
- params: { rid },
- right: this.renderDisclosure
- });
- }
-
- if (canReturnQueue) {
- sections[2].data.push({
- icon: 'undo',
- name: I18n.t('Return'),
- event: this.returnLivechat,
- right: this.renderDisclosure
- });
- }
-
- sections[2].data.push({
- icon: 'history',
- name: I18n.t('Navigation_history'),
- route: 'VisitorNavigationView',
- params: { rid },
- right: this.renderDisclosure
- });
- }
-
- sections.push({
- data: [notificationsAction],
- renderItem: this.renderItem
- });
- }
-
- // If can edit this room
- // If this room type can be Encrypted
- // If e2e is enabled for this server
- if (canEdit && E2E_ROOM_TYPES[t] && e2eEnabled) {
- sections.splice(2, 0, {
- data: [{
- icon: 'encrypted',
- name: I18n.t('Encrypted'),
- testID: 'room-actions-encrypt',
- right: this.renderEncryptedSwitch
- }],
- renderItem: this.renderItem
- });
- }
-
- return sections;
- }
-
- renderDisclosure = () => {
- const { theme } = this.props;
- return ;
- }
-
- renderSeparator = () => {
- const { theme } = this.props;
- return ;
- }
-
renderEncryptedSwitch = () => {
const { room } = this.state;
const { encrypted } = room;
@@ -523,7 +242,6 @@ class RoomActionsView extends React.Component {
value={encrypted}
trackColor={SWITCH_TRACK_COLOR}
onValueChange={this.toggleEncrypted}
- style={styles.encryptedSwitch}
/>
);
}
@@ -667,128 +385,467 @@ class RoomActionsView extends React.Component {
);
}
- renderRoomInfo = ({ item }) => {
+ renderRoomInfo = () => {
const { room, member } = this.state;
const {
- name,
- t,
- rid,
- topic
+ rid, name, t, topic
} = room;
- const { theme } = this.props;
+ const { theme, fontScale } = this.props;
const avatar = RocketChat.getRoomAvatar(room);
+ const isGroupChat = RocketChat.isGroupChat(room);
return (
- this.renderTouchableItem((
- <>
-
- {t === 'd' && member._id ? : null }
-
-
- {room.t === 'd'
- ? {room.fname}
- : (
-
-
- {RocketChat.getRoomTitle(room)}
-
- )
+
+
+ this.onPressTouchable({
+ route: 'RoomInfoView',
+ // forward room only if room isn't joined
+ params: {
+ rid, t, room, member
}
-
- {room.t === 'd' && }
+ })}
+ style={{ backgroundColor: themes[theme].backgroundColor }}
+ accessibilityLabel={I18n.t('Room_Info')}
+ accessibilityTraits='button'
+ enabled={!isGroupChat}
+ testID='room-actions-info'
+ theme={theme}
+ >
+
+
+ {t === 'd' && member._id ? : null }
+
+
+ {room.t === 'd'
+ ? {room.fname}
+ : (
+
+
+ {RocketChat.getRoomTitle(room)}
+
+ )
+ }
+
+ {room.t === 'd' && }
+
+ {isGroupChat ? null : }
- {!item.disabled && }
- >
- ), item)
+
+
+
);
}
- renderTouchableItem = (subview, item) => {
- const { theme } = this.props;
- return (
- this.onPressTouchable(item)}
- style={{ backgroundColor: themes[theme].backgroundColor }}
- accessibilityLabel={item.name}
- accessibilityTraits='button'
- enabled={!item.disabled}
- testID={item.testID}
- theme={theme}
- >
-
- {subview}
-
-
- );
- }
-
- renderItem = ({ item }) => {
- const { theme } = this.props;
- const colorDanger = { color: themes[theme].dangerColor };
- const subview = item.type === 'danger' ? (
- <>
-
- { item.name }
- >
- ) : (
- <>
-
- { item.name }
- {item.description ? { item.description } : null}
- {item?.right?.()}
- >
- );
- return this.renderTouchableItem(subview, item);
- }
-
- renderSectionSeparator = (data) => {
- const { theme } = this.props;
- if (data.trailingItem) {
- return ;
+ renderJitsi = () => {
+ const { room } = this.state;
+ const { jitsiEnabled } = this.props;
+ if (!jitsiEnabled) {
+ return null;
}
- if (!data.trailingSection) {
- return ;
+ return (
+
+
+ RocketChat.callJitsi(room?.rid, true)}
+ testID='room-actions-voice'
+ left={() => }
+ showActionIndicator
+ />
+
+ RocketChat.callJitsi(room?.rid)}
+ testID='room-actions-video'
+ left={() => }
+ showActionIndicator
+ />
+
+
+ );
+ }
+
+ renderE2EEncryption = () => {
+ const {
+ room, canEdit
+ } = this.state;
+ const { e2eEnabled } = this.props;
+
+ // If can edit this room
+ // If this room type can be Encrypted
+ // If e2e is enabled for this server
+ if (canEdit && E2E_ROOM_TYPES[room?.t] && e2eEnabled) {
+ return (
+
+
+ }
+ right={this.renderEncryptedSwitch}
+ />
+
+
+ );
}
return null;
}
- render() {
+ renderLastSection = () => {
+ const { room, joined } = this.state;
const { theme } = this.props;
+ const { t, blocker } = room;
+
+ if (!joined || t === 'l') {
+ return null;
+ }
+
+ if (t === 'd') {
+ return (
+
+
+ this.onPressTouchable({
+ event: this.toggleBlockUser
+ })}
+ testID='room-actions-block-user'
+ left={() => }
+ showActionIndicator
+ color={themes[theme].dangerColor}
+ />
+
+
+ );
+ }
+
+ if (t === 'p' || t === 'c') {
+ return (
+
+
+ this.onPressTouchable({
+ event: this.leaveChannel
+ })}
+ testID='room-actions-leave-channel'
+ left={() => }
+ showActionIndicator
+ color={themes[theme].dangerColor}
+ />
+
+
+ );
+ }
+ }
+
+ render() {
+ const {
+ room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate, canForwardGuest, canReturnQueue
+ } = this.state;
+ const {
+ rid, t, encrypted
+ } = room;
+ const isGroupChat = RocketChat.isGroupChat(room);
return (
-
-
- item.name}
- testID='room-actions-list'
- {...scrollPersistTaps}
- />
+
+
+
+ {this.renderRoomInfo()}
+ {this.renderJitsi()}
+ {this.renderE2EEncryption()}
+
+
+
+ {(['c', 'p'].includes(t) && canViewMembers) || isGroupChat
+ ? (
+ <>
+ 0 ? `${ membersCount } ${ I18n.t('members') }` : null}
+ onPress={() => this.onPressTouchable({ route: 'RoomMembersView', params: { rid, room } })}
+ testID='room-actions-members'
+ left={() => }
+ showActionIndicator
+ translateSubtitle={false}
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p'].includes(t) && canAddUser
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'SelectedUsersView',
+ params: {
+ rid,
+ title: I18n.t('Add_users'),
+ nextAction: this.addUser
+ }
+ })}
+ testID='room-actions-add-user'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p'].includes(t) && canInviteUser
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'InviteUsersView',
+ params: { rid }
+ })}
+ testID='room-actions-invite-user'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'MessagesView',
+ params: { rid, t, name: 'Files' }
+ })}
+ testID='room-actions-files'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'MessagesView',
+ params: { rid, t, name: 'Mentions' }
+ })}
+ testID='room-actions-mentioned'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'MessagesView',
+ params: { rid, t, name: 'Starred' }
+ })}
+ testID='room-actions-starred'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'SearchMessagesView',
+ params: { rid, encrypted }
+ })}
+ testID='room-actions-search'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ event: this.handleShare
+ })}
+ testID='room-actions-share'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t)
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'MessagesView',
+ params: { rid, t, name: 'Pinned' }
+ })}
+ testID='room-actions-pinned'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t) && canAutoTranslate
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'AutoTranslateView',
+ params: { rid, room }
+ })}
+ testID='room-actions-auto-translate'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['c', 'p', 'd'].includes(t) && joined
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'NotificationPrefView',
+ params: { rid, room }
+ })}
+ testID='room-actions-notifications'
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['l'].includes(t) && !this.isOmnichannelPreview
+ ? (
+ <>
+ this.onPressTouchable({
+ event: this.closeLivechat
+ })}
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['l'].includes(t) && !this.isOmnichannelPreview && canForwardGuest
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'ForwardLivechatView',
+ params: { rid }
+ })}
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['l'].includes(t) && !this.isOmnichannelPreview && canReturnQueue
+ ? (
+ <>
+ this.onPressTouchable({
+ event: this.returnLivechat
+ })}
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+ {['l'].includes(t) && !this.isOmnichannelPreview
+ ? (
+ <>
+ this.onPressTouchable({
+ route: 'VisitorNavigationView',
+ params: { rid }
+ })}
+ left={() => }
+ showActionIndicator
+ />
+
+ >
+ )
+ : null}
+
+
+ {this.renderLastSection()}
+
);
}
}
const mapStateToProps = state => ({
- user: getUserSelector(state),
- baseUrl: state.server.server,
jitsiEnabled: state.settings.Jitsi_Enabled || false,
e2eEnabled: state.settings.E2E_Enable || false
});
@@ -799,4 +856,4 @@ const mapDispatchToProps = dispatch => ({
setLoadingInvite: loading => dispatch(setLoadingAction(loading))
});
-export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RoomActionsView));
+export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withDimensions(RoomActionsView)));
diff --git a/app/views/RoomActionsView/styles.js b/app/views/RoomActionsView/styles.js
index 56d2b5366..a5476f8fb 100644
--- a/app/views/RoomActionsView/styles.js
+++ b/app/views/RoomActionsView/styles.js
@@ -1,51 +1,20 @@
import { StyleSheet } from 'react-native';
+import { PADDING_HORIZONTAL } from '../../containers/List/constants';
import sharedStyles from '../Styles';
export default StyleSheet.create({
- contentContainer: {
- paddingBottom: 30
- },
- container: {
- flex: 1
- },
- sectionItem: {
- paddingVertical: 11,
+ roomInfoContainer: {
+ paddingHorizontal: PADDING_HORIZONTAL,
flexDirection: 'row',
alignItems: 'center'
},
- sectionItemIcon: {
- width: 56,
- textAlign: 'center'
- },
- sectionItemName: {
- flex: 1,
- fontSize: 14,
- ...sharedStyles.textRegular
- },
- sectionItemDescription: {
- fontSize: 14,
- ...sharedStyles.textRegular
- },
- separator: {
- height: StyleSheet.hairlineWidth
- },
- sectionSeparator: {
- borderBottomWidth: StyleSheet.hairlineWidth,
- height: 36
- },
- sectionSeparatorBorder: {
- borderTopWidth: StyleSheet.hairlineWidth
- },
avatar: {
- marginHorizontal: 16
+ marginRight: PADDING_HORIZONTAL
},
roomTitleContainer: {
flex: 1
},
- roomTitlePadding: {
- paddingRight: 16
- },
roomTitle: {
fontSize: 16,
...sharedStyles.textMedium
@@ -58,8 +27,5 @@ export default StyleSheet.create({
paddingRight: 16,
flexDirection: 'row',
alignItems: 'center'
- },
- encryptedSwitch: {
- marginHorizontal: 16
}
});
diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js
index 92abe031e..2d2952231 100644
--- a/app/views/RoomInfoEditView/index.js
+++ b/app/views/RoomInfoEditView/index.js
@@ -418,10 +418,9 @@ class RoomInfoEditView extends React.Component {
contentContainerStyle={sharedStyles.container}
keyboardVerticalOffset={128}
>
-
+
-
+
diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js
index e7829dbdb..340a4e795 100644
--- a/app/views/RoomMembersView/index.js
+++ b/app/views/RoomMembersView/index.js
@@ -250,8 +250,8 @@ class RoomMembersView extends React.Component {
} = this.state;
const { theme } = this.props;
return (
-
-
+
+
-
+
-
+
+
{this.renderHeader()}
{this.renderScroll()}
{showSortDropdown ? (
diff --git a/app/views/ScreenLockConfigView.js b/app/views/ScreenLockConfigView.js
index 0dfb377f2..bf0f6a15c 100644
--- a/app/views/ScreenLockConfigView.js
+++ b/app/views/ScreenLockConfigView.js
@@ -1,32 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { StyleSheet, Switch, ScrollView } from 'react-native';
+import { Switch } from 'react-native';
import { connect } from 'react-redux';
import I18n from '../i18n';
import { withTheme } from '../theme';
import { themes, SWITCH_TRACK_COLOR } from '../constants/colors';
import StatusBar from '../containers/StatusBar';
-import Separator from '../containers/Separator';
-import ListItem from '../containers/ListItem';
-import ItemInfo from '../containers/ItemInfo';
-import { CustomIcon } from '../lib/Icons';
+import * as List from '../containers/List';
import database from '../lib/database';
import { supportedBiometryLabel, changePasscode, checkHasPasscode } from '../utils/localAuthentication';
-import { DisclosureImage } from '../containers/DisclosureIndicator';
import { DEFAULT_AUTO_LOCK } from '../constants/localAuthentication';
import SafeAreaView from '../containers/SafeAreaView';
import { events, logEvent } from '../utils/log';
-const styles = StyleSheet.create({
- listPadding: {
- paddingVertical: 36
- },
- emptySpace: {
- marginTop: 36
- }
-});
-
const DEFAULT_BIOMETRY = false;
class ScreenLockConfigView extends React.Component {
@@ -161,29 +148,23 @@ class ScreenLockConfigView extends React.Component {
this.setState({ autoLockTime }, () => this.save());
}
- renderSeparator = () => {
- const { theme } = this.props;
- return ;
- }
-
renderIcon = () => {
const { theme } = this.props;
- return ;
+ return ;
}
renderItem = ({ item }) => {
- const { theme } = this.props;
const { title, value, disabled } = item;
return (
<>
- this.changeAutoLockTime(value)}
right={this.isSelected(value) ? this.renderIcon : null}
- theme={theme}
disabled={disabled}
+ translateTitle={false}
/>
-
+
>
);
}
@@ -214,7 +195,7 @@ class ScreenLockConfigView extends React.Component {
renderAutoLockItems = () => {
const { autoLock, autoLockTime } = this.state;
- const { theme, Force_Screen_Lock_After, Force_Screen_Lock } = this.props;
+ const { Force_Screen_Lock_After, Force_Screen_Lock } = this.props;
if (!autoLock) {
return null;
}
@@ -233,75 +214,62 @@ class ScreenLockConfigView extends React.Component {
});
}
return (
- <>
-
+
+
{items.map(item => this.renderItem({ item }))}
- >
+
);
}
- renderDisclosure = () => {
- const { theme } = this.props;
- return ;
- }
-
renderBiometry = () => {
const { autoLock, biometryLabel } = this.state;
- const { theme } = this.props;
if (!autoLock || !biometryLabel) {
return null;
}
return (
- <>
-
-
+
+ this.renderBiometrySwitch()}
- theme={theme}
+ translateTitle={false}
/>
-
- >
+
+
);
}
render() {
const { autoLock } = this.state;
- const { theme } = this.props;
return (
-
-
- item.value}
- contentContainerStyle={styles.listPadding}
- >
-
- this.renderAutoLockSwitch()}
- theme={theme}
- />
- {autoLock
- ? (
- <>
-
-
- >
- )
- : null
- }
-
-
+
+
+
+
+
+ this.renderAutoLockSwitch()}
+ />
+ {autoLock
+ ? (
+ <>
+
+
+ >
+ )
+ : null
+ }
+
+
+
{this.renderBiometry()}
{this.renderAutoLockItems()}
-
+
);
}
diff --git a/app/views/SearchMessagesView/index.js b/app/views/SearchMessagesView/index.js
index 607711eb6..37dfc8b11 100644
--- a/app/views/SearchMessagesView/index.js
+++ b/app/views/SearchMessagesView/index.js
@@ -183,8 +183,8 @@ class SearchMessagesView extends React.Component {
render() {
const { theme } = this.props;
return (
-
-
+
+
-
+
+
{
- const { loading, theme } = this.props;
+ const { loading } = this.props;
return (
-
-
+
+
{this.renderList()}
diff --git a/app/views/SetUsernameView.js b/app/views/SetUsernameView.js
index 2025bc91e..ccae5d036 100644
--- a/app/views/SetUsernameView.js
+++ b/app/views/SetUsernameView.js
@@ -104,9 +104,9 @@ class SetUsernameView extends React.Component {
style={{ backgroundColor: themes[theme].auxiliaryBackground }}
contentContainerStyle={sharedStyles.container}
>
-
+
-
+
(
-
-));
-SectionSeparator.propTypes = {
- theme: PropTypes.string
-};
-
class SettingsView extends React.Component {
static navigationOptions = ({ navigation, isMasterDetail }) => ({
headerLeft: () => (isMasterDetail ? (
@@ -223,11 +202,6 @@ class SettingsView extends React.Component {
openLink(LICENSE_LINK, theme);
}
- renderDisclosure = () => {
- const { theme } = this.props;
- return ;
- }
-
renderCrashReportSwitch = () => {
const { allowCrashReport } = this.props;
return (
@@ -253,170 +227,153 @@ class SettingsView extends React.Component {
render() {
const { server, isMasterDetail, theme } = this.props;
return (
-
-
-
+
+
+
{isMasterDetail ? (
<>
-
-
-
- this.navigateToScreen('ProfileView')}
- showActionIndicator
- testID='settings-profile'
- right={this.renderDisclosure}
- theme={theme}
- />
+
+
+
+
+
+
+
+ this.navigateToScreen('ProfileView')}
+ showActionIndicator
+ testID='settings-profile'
+ />
+
+
>
) : null}
-
-
-
- this.navigateToScreen('LanguageView')}
- showActionIndicator
- testID='settings-view-language'
- right={this.renderDisclosure}
- theme={theme}
- />
-
- {!isFDroidBuild ? (
- <>
-
- >
- ) : null}
-
-
-
- this.navigateToScreen('DefaultBrowserView')}
- testID='settings-view-default-browser'
- right={this.renderDisclosure}
- theme={theme}
- />
-
- this.navigateToScreen('ThemeView')}
- testID='settings-view-theme'
- right={this.renderDisclosure}
- theme={theme}
- />
-
- this.navigateToScreen('ScreenLockConfigView')}
- right={this.renderDisclosure}
- theme={theme}
- />
+
+
+
+
+ this.navigateToScreen('LanguageView')}
+ showActionIndicator
+ testID='settings-view-language'
+ />
+
+ {!isFDroidBuild ? (
+ <>
+
+ >
+ ) : null}
+
+
+
+ this.navigateToScreen('DefaultBrowserView')}
+ testID='settings-view-default-browser'
+ />
+
+ this.navigateToScreen('ThemeView')}
+ testID='settings-view-theme'
+ />
+
+ this.navigateToScreen('ScreenLockConfigView')}
+ />
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
{!isFDroidBuild ? (
<>
- this.renderAnalyticsEventsSwitch()}
- theme={theme}
- />
-
- this.renderCrashReportSwitch()}
- theme={theme}
- />
-
-
-
+
+
+ this.renderAnalyticsEventsSwitch()}
+ />
+
+ this.renderCrashReportSwitch()}
+ />
+
+
+
>
) : null}
-
-
-
-
-
+
+
+
+
+
+
+
+
);
}
diff --git a/app/views/SettingsView/styles.js b/app/views/SettingsView/styles.js
deleted file mode 100644
index 2bf7cdaeb..000000000
--- a/app/views/SettingsView/styles.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { StyleSheet } from 'react-native';
-
-import sharedStyles from '../Styles';
-
-export default StyleSheet.create({
- sectionSeparatorBorder: {
- ...sharedStyles.separatorVertical,
- height: 36
- },
- listPadding: {
- paddingVertical: 36
- }
-});
diff --git a/app/views/ShareListView/index.js b/app/views/ShareListView/index.js
index 1f94ee743..1f3a3b7dd 100644
--- a/app/views/ShareListView/index.js
+++ b/app/views/ShareListView/index.js
@@ -458,10 +458,9 @@ class ShareListView extends React.Component {
}
render() {
- const { theme } = this.props;
return (
-
-
+
+
{this.renderContent()}
);
diff --git a/app/views/ShareView/index.js b/app/views/ShareView/index.js
index 2ec601f95..6b41ef24f 100644
--- a/app/views/ShareView/index.js
+++ b/app/views/ShareView/index.js
@@ -324,7 +324,6 @@ class ShareView extends Component {
return (
{this.renderContent()}
diff --git a/app/views/SidebarView/index.js b/app/views/SidebarView/index.js
index 3caf06da0..9dd63b8dc 100644
--- a/app/views/SidebarView/index.js
+++ b/app/views/SidebarView/index.js
@@ -215,7 +215,7 @@ class Sidebar extends Component {
return null;
}
return (
-
+
{
- const { theme } = this.props;
- return ;
- }
-
renderHeader = () => {
const { statusText } = this.state;
const { user, theme } = this.props;
@@ -157,18 +147,18 @@ class StatusView extends React.Component {
placeholder={I18n.t('What_are_you_doing_right_now')}
testID='status-view-input'
/>
-
+
>
);
}
renderItem = ({ item }) => {
const { statusText } = this.state;
- const { theme, user } = this.props;
+ const { user } = this.props;
const { id, name } = item;
return (
- {
logEvent(events[`STATUS_${ item.id.toUpperCase() }`]);
if (user.status !== item.id) {
@@ -184,25 +174,22 @@ class StatusView extends React.Component {
}
}}
testID={`status-view-${ id }`}
- left={() => }
- theme={theme}
+ left={() => }
/>
);
}
render() {
const { loading } = this.state;
- const { theme } = this.props;
return (
-
+
item.id}
- contentContainerStyle={{ borderColor: themes[theme].separatorColor }}
renderItem={this.renderItem}
ListHeaderComponent={this.renderHeader}
- ListFooterComponent={() => }
- ItemSeparatorComponent={this.renderSeparator}
+ ListFooterComponent={List.Separator}
+ ItemSeparatorComponent={List.Separator}
/>
diff --git a/app/views/Styles.js b/app/views/Styles.js
index d04cde69a..394e90918 100644
--- a/app/views/Styles.js
+++ b/app/views/Styles.js
@@ -121,11 +121,6 @@ export default StyleSheet.create({
inputLastChild: {
marginBottom: 15
},
- listContentContainer: {
- borderTopWidth: StyleSheet.hairlineWidth,
- borderBottomWidth: StyleSheet.hairlineWidth,
- marginVertical: 36
- },
notchLandscapeContainer: {
marginTop: -34,
paddingHorizontal: 30
diff --git a/app/views/ThemeView.js b/app/views/ThemeView.js
index 2686e3b69..e62d7ca58 100644
--- a/app/views/ThemeView.js
+++ b/app/views/ThemeView.js
@@ -1,17 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {
- FlatList, Text, View, StyleSheet
-} from 'react-native';
import I18n from '../i18n';
import { withTheme } from '../theme';
import { themes } from '../constants/colors';
-import sharedStyles from './Styles';
import StatusBar from '../containers/StatusBar';
-import Separator from '../containers/Separator';
-import ListItem from '../containers/ListItem';
-import { CustomIcon } from '../lib/Icons';
+import * as List from '../containers/List';
import { THEME_PREFERENCES_KEY } from '../lib/rocketchat';
import { supportSystemTheme } from '../utils/deviceInfo';
import SafeAreaView from '../containers/SafeAreaView';
@@ -39,8 +33,6 @@ const THEMES = [
}, {
label: 'Dark',
value: 'dark',
- separator: true,
- header: 'Dark_level',
group: DARK_GROUP
}, {
label: 'Black',
@@ -53,20 +45,8 @@ if (supportSystemTheme()) {
THEMES.unshift(SYSTEM_THEME);
}
-const styles = StyleSheet.create({
- list: {
- paddingBottom: 18
- },
- info: {
- paddingTop: 25,
- paddingBottom: 18,
- paddingHorizontal: 16
- },
- infoText: {
- fontSize: 16,
- ...sharedStyles.textRegular
- }
-});
+const themeGroup = THEMES.filter(item => item.group === THEME_GROUP);
+const darkGroup = THEMES.filter(item => item.group === DARK_GROUP);
class ThemeView extends React.Component {
static navigationOptions = () => ({
@@ -114,74 +94,44 @@ class ThemeView extends React.Component {
await UserPreferences.setMapAsync(THEME_PREFERENCES_KEY, newTheme);
};
- renderSeparator = () => {
- const { theme } = this.props;
- return ;
- }
-
renderIcon = () => {
const { theme } = this.props;
- return ;
+ return ;
}
- renderItem = ({ item, index }) => {
- const { theme } = this.props;
+ renderItem = ({ item }) => {
const { label, value } = item;
- const isFirst = index === 0;
return (
<>
- {item.separator || isFirst ? this.renderSectionHeader(item.header) : null}
- this.onClick(item)}
testID={`theme-view-${ value }`}
right={this.isSelected(item) ? this.renderIcon : null}
- theme={theme}
/>
+
>
);
}
- renderSectionHeader = (header = 'Theme') => {
- const { theme } = this.props;
- return (
- <>
-
- {I18n.t(header)}
-
- {this.renderSeparator()}
- >
- );
- }
-
- renderFooter = () => {
- const { theme } = this.props;
- return (
-
-
- {I18n.t('Applying_a_theme_will_change_how_the_app_looks')}
-
-
- );
- }
-
render() {
- const { theme } = this.props;
return (
-
-
- item.value + item.group}
- contentContainerStyle={[
- styles.list,
- { borderColor: themes[theme].separatorColor }
- ]}
- renderItem={this.renderItem}
- ListHeaderComponent={this.renderHeader}
- ListFooterComponent={this.renderFooter}
- ItemSeparatorComponent={this.renderSeparator}
- />
+
+
+
+
+
+ {
+ themeGroup.map(item => this.renderItem({ item }))
+ }
+
+
+
+ {
+ darkGroup.map(item => this.renderItem({ item }))
+ }
+
+
);
}
diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js
index 3f319436c..112461586 100644
--- a/app/views/ThreadMessagesView/index.js
+++ b/app/views/ThreadMessagesView/index.js
@@ -334,8 +334,8 @@ class ThreadMessagesView extends React.Component {
}
return (
-
-
+
+
(
-
- {info}
-
-));
-
-Info.propTypes = {
- info: PropTypes.string,
- theme: PropTypes.string
-};
-
-export default Info;
diff --git a/app/views/UserNotificationPreferencesView/SectionSeparator.js b/app/views/UserNotificationPreferencesView/SectionSeparator.js
deleted file mode 100644
index 88acd1a0e..000000000
--- a/app/views/UserNotificationPreferencesView/SectionSeparator.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import {
- View
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-import styles from './styles';
-import { themes } from '../../constants/colors';
-
-const SectionSeparator = React.memo(({ theme }) => (
-
-));
-
-SectionSeparator.propTypes = {
- theme: PropTypes.string
-};
-
-export default SectionSeparator;
diff --git a/app/views/UserNotificationPreferencesView/SectionTitle.js b/app/views/UserNotificationPreferencesView/SectionTitle.js
deleted file mode 100644
index e93cb0e01..000000000
--- a/app/views/UserNotificationPreferencesView/SectionTitle.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import {
- Text
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-import styles from './styles';
-import { themes } from '../../constants/colors';
-
-const SectionTitle = React.memo(({ title, theme }) => (
-
- {title}
-
-));
-
-SectionTitle.propTypes = {
- title: PropTypes.string,
- theme: PropTypes.string
-};
-
-export default SectionTitle;
diff --git a/app/views/UserNotificationPreferencesView/index.js b/app/views/UserNotificationPreferencesView/index.js
index e07888594..085fbe8ac 100644
--- a/app/views/UserNotificationPreferencesView/index.js
+++ b/app/views/UserNotificationPreferencesView/index.js
@@ -1,27 +1,26 @@
import React from 'react';
-import {
- View, ScrollView, Text
-} from 'react-native';
+import { Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { themes } from '../../constants/colors';
import StatusBar from '../../containers/StatusBar';
-import ListItem from '../../containers/ListItem';
-import Separator from '../../containers/Separator';
+import * as List from '../../containers/List';
import I18n from '../../i18n';
-import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import styles from './styles';
import RocketChat from '../../lib/rocketchat';
import { withTheme } from '../../theme';
import SafeAreaView from '../../containers/SafeAreaView';
-import SectionTitle from './SectionTitle';
-import SectionSeparator from './SectionSeparator';
-import Info from './Info';
import { OPTIONS } from './options';
import ActivityIndicator from '../../containers/ActivityIndicator';
-import { DisclosureImage } from '../../containers/DisclosureIndicator';
import { getUserSelector } from '../../selectors/login';
+import sharedStyles from '../Styles';
+
+const styles = StyleSheet.create({
+ pickerText: {
+ ...sharedStyles.textRegular,
+ fontSize: 16
+ }
+});
class UserNotificationPreferencesView extends React.Component {
static navigationOptions = () => ({
@@ -30,7 +29,6 @@ class UserNotificationPreferencesView extends React.Component {
static propTypes = {
navigation: PropTypes.object,
- route: PropTypes.object,
theme: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.string
@@ -90,72 +88,55 @@ class UserNotificationPreferencesView extends React.Component {
this.setState({ preferences: settings.preferences });
}
- renderDisclosure = () => {
- const { theme } = this.props;
- return ;
- }
-
render() {
const { theme } = this.props;
const { loading } = this.state;
return (
-
-
-
+
+
+
{loading
? (
<>
-
-
+
+
+ this.pickerSelection(title, 'desktopNotifications')}
+ right={() => this.renderPickerOption('desktopNotifications')}
+ />
+
+
+
- this.pickerSelection(title, 'desktopNotifications')}
- right={() => this.renderPickerOption('desktopNotifications')}
- theme={theme}
- />
-
-
+
+
+ this.pickerSelection(title, 'mobileNotifications')}
+ right={() => this.renderPickerOption('mobileNotifications')}
+ />
+
+
+
-
-
-
-
- this.pickerSelection(title, 'mobileNotifications')}
- right={() => this.renderPickerOption('mobileNotifications')}
- theme={theme}
- />
-
-
-
-
-
-
-
- this.pickerSelection(title, 'emailNotificationMode')}
- right={() => this.renderPickerOption('emailNotificationMode')}
- theme={theme}
- />
-
-
-
+
+
+ this.pickerSelection(title, 'emailNotificationMode')}
+ right={() => this.renderPickerOption('emailNotificationMode')}
+ />
+
+
+
>
) :
}
-
-
+
);
}
diff --git a/app/views/UserNotificationPreferencesView/styles.js b/app/views/UserNotificationPreferencesView/styles.js
deleted file mode 100644
index 9b4c9e0e6..000000000
--- a/app/views/UserNotificationPreferencesView/styles.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { StyleSheet } from 'react-native';
-
-import sharedStyles from '../Styles';
-
-export default StyleSheet.create({
- sectionSeparatorBorder: {
- height: 10
- },
- marginBottom: {
- height: 30
- },
- contentContainer: {
- marginVertical: 10
- },
- infoText: {
- ...sharedStyles.textRegular,
- fontSize: 13,
- paddingHorizontal: 15,
- paddingVertical: 10
- },
- sectionTitle: {
- ...sharedStyles.separatorBottom,
- paddingHorizontal: 15,
- paddingVertical: 10,
- fontSize: 14
- },
- pickerText: {
- ...sharedStyles.textRegular,
- fontSize: 16
- }
-});
diff --git a/app/views/UserPreferencesView/index.js b/app/views/UserPreferencesView/index.js
index 096736b7c..215b730b6 100644
--- a/app/views/UserPreferencesView/index.js
+++ b/app/views/UserPreferencesView/index.js
@@ -1,18 +1,13 @@
import React from 'react';
-import { ScrollView } from 'react-native';
import PropTypes from 'prop-types';
import I18n from '../../i18n';
import {
logEvent, events
} from '../../utils/log';
-import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import Separator from '../../containers/Separator';
import SafeAreaView from '../../containers/SafeAreaView';
import StatusBar from '../../containers/StatusBar';
-import ListItem from '../../containers/ListItem';
-import { DisclosureImage } from '../../containers/DisclosureIndicator';
-import { withTheme } from '../../theme';
+import * as List from '../../containers/List';
class UserPreferencesView extends React.Component {
static navigationOptions = () => ({
@@ -20,13 +15,7 @@ class UserPreferencesView extends React.Component {
});
static propTypes = {
- navigation: PropTypes.object,
- theme: PropTypes.string
- }
-
- renderDisclosure = () => {
- const { theme } = this.props;
- return ;
+ navigation: PropTypes.object
}
navigateToScreen = (screen, params) => {
@@ -36,30 +25,24 @@ class UserPreferencesView extends React.Component {
}
render() {
- const { theme } = this.props;
-
return (
-
-
-
- this.navigateToScreen('UserNotificationPrefView')}
- showActionIndicator
- testID='preferences-view-notifications'
- right={this.renderDisclosure}
- theme={theme}
- />
-
-
+
+
+
+
+
+ this.navigateToScreen('UserNotificationPrefView')}
+ showActionIndicator
+ testID='preferences-view-notifications'
+ />
+
+
+
);
}
}
-export default withTheme(UserPreferencesView);
+export default UserPreferencesView;
diff --git a/app/views/VisitorNavigationView.js b/app/views/VisitorNavigationView.js
index 3da667699..be50ddc19 100644
--- a/app/views/VisitorNavigationView.js
+++ b/app/views/VisitorNavigationView.js
@@ -5,12 +5,12 @@ import PropTypes from 'prop-types';
import { withTheme } from '../theme';
import RocketChat from '../lib/rocketchat';
import { themes } from '../constants/colors';
-import Separator from '../containers/Separator';
import openLink from '../utils/openLink';
import I18n from '../i18n';
import debounce from '../utils/debounce';
import sharedStyles from './Styles';
-import ListItem from '../containers/ListItem';
+import * as List from '../containers/List';
+import SafeAreaView from '../containers/SafeAreaView';
const styles = StyleSheet.create({
noResult: {
@@ -18,23 +18,18 @@ const styles = StyleSheet.create({
paddingVertical: 56,
...sharedStyles.textAlignCenter,
...sharedStyles.textSemibold
- },
- withoutBorder: {
- borderBottomWidth: 0,
- borderTopWidth: 0
}
});
-const Item = ({ item, theme }) => (
- (
+ openLink(item.navigation?.page?.location?.href)}
- theme={theme}
+ translateTitle={false}
/>
);
Item.propTypes = {
- item: PropTypes.object,
- theme: PropTypes.string
+ item: PropTypes.object
};
const VisitorNavigationView = ({ route, theme }) => {
@@ -67,24 +62,20 @@ const VisitorNavigationView = ({ route, theme }) => {
}, 300);
return (
- }
- ItemSeparatorComponent={() => }
- contentContainerStyle={[
- sharedStyles.listContentContainer,
- {
- backgroundColor: themes[theme].auxiliaryBackground,
- borderColor: themes[theme].separatorColor
- },
- !pages.length && styles.withoutBorder
- ]}
- style={{ backgroundColor: themes[theme].auxiliaryBackground }}
- ListEmptyComponent={() => {I18n.t('No_results_found')}}
- keyExtractor={item => item}
- onEndReached={onEndReached}
- onEndReachedThreshold={5}
- />
+
+ }
+ ItemSeparatorComponent={List.Separator}
+ ListFooterComponent={List.Separator}
+ ListHeaderComponent={List.Separator}
+ contentContainerStyle={List.styles.contentContainerStyleFlatList}
+ ListEmptyComponent={() => {I18n.t('No_results_found')}}
+ keyExtractor={item => item}
+ onEndReached={onEndReached}
+ onEndReachedThreshold={5}
+ />
+
);
};
VisitorNavigationView.propTypes = {
diff --git a/e2e/tests/assorted/06-status.spec.js b/e2e/tests/assorted/06-status.spec.js
index 2ddd54e6b..45c4c6f96 100644
--- a/e2e/tests/assorted/06-status.spec.js
+++ b/e2e/tests/assorted/06-status.spec.js
@@ -37,7 +37,7 @@ describe('Status screen', () => {
describe('Usage', async () => {
it('should change status', async () => {
await element(by.id('status-view-busy')).tap();
- await expect(element(by.id('status-view-current-busy'))).toExist();
+ await waitFor(element(by.id('status-view-current-busy'))).toExist().withTimeout(2000);
});
it('should change status text', async () => {
diff --git a/e2e/tests/room/04-roominfo.spec.js b/e2e/tests/room/04-roominfo.spec.js
index 3f4ee175d..e687c0bbf 100644
--- a/e2e/tests/room/04-roominfo.spec.js
+++ b/e2e/tests/room/04-roominfo.spec.js
@@ -15,7 +15,7 @@ async function navigateToRoomInfo(type) {
}
await searchRoom(room);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
- await element(by.id(`rooms-list-view-item-${ room }`)).tap();
+ await element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
await element(by.id('room-view-header-actions')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
diff --git a/storybook/index.js b/storybook/index.js
index 924e91deb..993860a87 100644
--- a/storybook/index.js
+++ b/storybook/index.js
@@ -5,7 +5,7 @@ import RNBootSplash from 'react-native-bootsplash';
import 'react-native-gesture-handler';
// eslint-disable-next-line no-undef
-jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => jest.fn(() => null));
+// jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => jest.fn(() => null));
RNBootSplash.hide();
diff --git a/storybook/stories/List.js b/storybook/stories/List.js
new file mode 100644
index 000000000..568fbc499
--- /dev/null
+++ b/storybook/stories/List.js
@@ -0,0 +1,196 @@
+/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types */
+import React from 'react';
+import { FlatList } from 'react-native';
+import { storiesOf } from '@storybook/react-native';
+
+import * as List from '../../app/containers/List';
+import SafeAreaView from '../../app/containers/SafeAreaView';
+import { longText } from '../utils';
+import { ThemeContext } from '../../app/theme';
+import { DimensionsContext } from '../../app/dimensions';
+
+const stories = storiesOf('List', module);
+
+stories.add('title and subtitle', () => (
+
+
+
+
+
+
+
+
+
+));
+
+stories.add('pressable', () => (
+
+
+ alert('Hi there!')} translateTitle={false} />
+
+ alert('Hi there!')} disabled translateTitle={false} />
+
+
+));
+
+
+stories.add('header', () => (
+
+
+
+
+));
+
+stories.add('icon', () => (
+
+
+
+));
+
+stories.add('separator', () => (
+
+
+
+));
+
+stories.add('with section and info', () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+));
+
+stories.add('with icon', () => (
+
+
+ } />
+
+ } />
+
+ }
+ right={() => }
+ />
+
+
+
+
+));
+
+stories.add('with custom color', () => (
+
+
+
+
+
+));
+
+const ListItemFull = ({ ...props }) => (
+ alert('Hi')}
+ left={() => }
+ right={() => }
+ {...props}
+ />
+);
+
+const ListFull = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+const ThemeStory = ({ theme }) => (
+
+
+
+);
+
+stories.add('with dark theme', () => );
+
+stories.add('with black theme', () => );
+
+const FontStory = ({ fontScale }) => (
+
+
+
+);
+
+/**
+ * It's going to test height only.
+ * Font scale on text and icons is applied based on OS setting
+ */
+stories.add('with small font', () => );
+
+stories.add('with bigger font', () => );
+
+stories.add('with FlatList', () => (
+
+ }
+ ListHeaderComponent={List.Separator}
+ ListFooterComponent={List.Separator}
+ ItemSeparatorComponent={List.Separator}
+ keyExtractor={item => item}
+ />
+
+));
diff --git a/storybook/stories/RoomItem.js b/storybook/stories/RoomItem.js
index 21169a41b..a4d221526 100644
--- a/storybook/stories/RoomItem.js
+++ b/storybook/stories/RoomItem.js
@@ -4,12 +4,12 @@ import { ScrollView, Dimensions } from 'react-native';
import { themes } from '../../app/constants/colors';
import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem';
+import { longText } from '../utils';
import StoriesSeparator from './StoriesSeparator';
const baseUrl = 'https://open.rocket.chat';
const { width } = Dimensions.get('window');
let _theme = 'light';
-const longText = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries';
const lastMessage = {
u: {
username: 'diego.mello'
diff --git a/storybook/stories/index.js b/storybook/stories/index.js
index 8848009d8..e857db496 100644
--- a/storybook/stories/index.js
+++ b/storybook/stories/index.js
@@ -5,6 +5,7 @@ import { createStore, combineReducers } from 'redux';
import { storiesOf } from '@storybook/react-native';
import RoomItem from './RoomItem';
+import './List';
import Message from './Message';
import UiKitMessage from './UiKitMessage';
import UiKitModal from './UiKitModal';
diff --git a/storybook/utils.js b/storybook/utils.js
new file mode 100644
index 000000000..83260dd02
--- /dev/null
+++ b/storybook/utils.js
@@ -0,0 +1 @@
+export const longText = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries';