MM-38682: Gekidou Homepage (Static) (#5756)

* Home page first pass

* Adds missing static elements, introduces button component

* Removes inlines styles

* Various clean ups and button component added

* Updates typography, and adds button util

* Removes button component

* Uses stylesheet.create for memoization

* Snapshots updated

* Podfile update / fix

* Flatlist!

* Tests updated

* Moves out server icon, styling fixes

* Sneaky buttons added, compass-icons list, and server_icon removed

* Snapshots

* Adds chevron to header

* Removes unnecessary files

* Tidies up header and error

* Address feedback

* Compass Icon const removed
This commit is contained in:
Shaz Amjad 2021-11-05 00:32:35 +11:00 committed by GitHub
parent f19c3b3b6c
commit 1c1d0e36aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 2859 additions and 131 deletions

View file

@ -10,9 +10,9 @@ import {fetchRoles} from '@actions/remote/role';
import {fetchConfigAndLicense} from '@actions/remote/systems';
import {fetchAllTeams, fetchMyTeams} from '@actions/remote/team';
import {fetchMe, updateAllUsersSinceLastDisconnect} from '@actions/remote/user';
import Events from '@app/constants/events';
import {General, WebsocketEvents} from '@constants';
import {SYSTEM_IDENTIFIERS} from '@constants/database';
import Events from '@constants/events';
import DatabaseManager from '@database/manager';
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
import {prepareMyChannelsForTeam} from '@queries/servers/channel';

View file

@ -0,0 +1,762 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Channels List should match snapshot 1`] = `
<View
style={
Array [
Object {
"backgroundColor": "#1e325c",
"flex": 1,
"paddingHorizontal": 20,
"paddingVertical": 10,
},
false,
]
}
>
<RNGestureHandlerButton
collapsable={false}
onGestureEvent={[Function]}
onGestureHandlerEvent={[Function]}
onGestureHandlerStateChange={[Function]}
onHandlerStateChange={[Function]}
rippleColor={0}
>
<View
accessible={true}
collapsable={false}
nativeID="animatedComponent"
style={
Object {
"opacity": 1,
}
}
>
<View>
<View
style={
Object {
"alignItems": "center",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<Text
style={
Object {
"color": "#ffffff",
"fontFamily": "Metropolis-SemiBold",
"fontSize": 28,
"fontWeight": "600",
"lineHeight": 36,
}
}
>
Contributors
</Text>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"marginLeft": 4,
}
}
>
<Icon
name="chevron-down"
style={
Object {
"color": "rgba(255,255,255,0.8)",
"fontSize": 24,
}
}
/>
</View>
</View>
</View>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"alignItems": "center",
"backgroundColor": "rgba(255,255,255,0.08)",
"borderRadius": 14,
"height": 28,
"justifyContent": "center",
"width": 28,
}
}
>
<Icon
name="plus"
style={
Object {
"color": "rgba(255,255,255,0.8)",
"fontSize": 18,
}
}
/>
</View>
</View>
</View>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 11,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
Community TEST
</Text>
</View>
</View>
</RNGestureHandlerButton>
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "rgba(255,255,255,0.12)",
"borderRadius": 8,
"flex": 1,
"flexDirection": "row",
"height": 40,
"justifyContent": "flex-start",
"marginVertical": 20,
"maxHeight": 40,
"padding": 8,
"width": "100%",
}
}
>
<Icon
name="magnify"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"width": 24,
}
}
/>
<TextInput
collapsable={false}
onGestureHandlerEvent={[Function]}
onGestureHandlerStateChange={[Function]}
placeholder="Find Channels"
placeholderTextColor="rgba(255,255,255,0.72)"
style={
Array [
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"textAlignVertical": "center",
},
],
Object {
"alignContent": "center",
"alignItems": "center",
"color": "#ffffff",
"flex": 1,
"height": 40,
"marginLeft": 5,
"marginTop": -2,
},
]
}
/>
</View>
<RCTScrollView
ListHeaderComponent={[Function]}
data={
Array [
Object {
"channels": Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "A Highlighted Channel!!!",
},
Object {
"id": "3",
"name": "And a longer channel name.",
},
],
"id": "1",
"title": "My first Category",
},
Object {
"channels": Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "A Highlighted Channel!!!",
},
Object {
"id": "3",
"name": "And a longer channel name.",
},
],
"id": "2",
"title": "Another Cat",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
style={
Object {
"flex": 1,
}
}
viewabilityConfigCallbackPairs={Array []}
>
<View>
<View
onLayout={[Function]}
>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View
style={
Object {
"display": "flex",
"flexDirection": "row",
}
}
>
<Icon
name="message-text-outline"
style={
Object {
"color": "#ffffff",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
],
Object {
"color": "#ffffff",
"paddingLeft": 12,
},
]
}
>
Threads
</Text>
</View>
</View>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"marginTop": 12,
"paddingVertical": 8,
}
}
>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 12,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
MY FIRST CATEGORY
</Text>
</View>
<View
data={
Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "A Highlighted Channel!!!",
},
Object {
"id": "3",
"name": "And a longer channel name.",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
viewabilityConfigCallbackPairs={Array []}
>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Just a channel
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
Object {
"color": "#ffffff",
},
]
}
>
A Highlighted Channel!!!
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
And a longer channel name.
</Text>
</View>
</View>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"marginTop": 12,
"paddingVertical": 8,
}
}
>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 12,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
ANOTHER CAT
</Text>
</View>
<View
data={
Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "A Highlighted Channel!!!",
},
Object {
"id": "3",
"name": "And a longer channel name.",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
viewabilityConfigCallbackPairs={Array []}
>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Just a channel
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
Object {
"color": "#ffffff",
},
]
}
>
A Highlighted Channel!!!
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
And a longer channel name.
</Text>
</View>
</View>
</View>
</View>
</View>
</RCTScrollView>
</View>
`;

View file

@ -0,0 +1,430 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Category List Component should match snapshot 1`] = `
<RCTScrollView
ListHeaderComponent={[Function]}
data={
Array [
Object {
"channels": Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "Highlighted!!!",
},
],
"id": "1",
"title": "My first Category",
},
Object {
"channels": Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "Highlighted!!!",
},
],
"id": "2",
"title": "Another cat",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
style={
Object {
"flex": 1,
}
}
viewabilityConfigCallbackPairs={Array []}
>
<View>
<View
onLayout={[Function]}
>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View
style={
Object {
"display": "flex",
"flexDirection": "row",
}
}
>
<Icon
name="message-text-outline"
style={
Object {
"color": "#ffffff",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
],
Object {
"color": "#ffffff",
"paddingLeft": 12,
},
]
}
>
Threads
</Text>
</View>
</View>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"marginTop": 12,
"paddingVertical": 8,
}
}
>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 12,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
MY FIRST CATEGORY
</Text>
</View>
<View
data={
Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "Highlighted!!!",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
viewabilityConfigCallbackPairs={Array []}
>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Just a channel
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
Object {
"color": "#ffffff",
},
]
}
>
Highlighted!!!
</Text>
</View>
</View>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"marginTop": 12,
"paddingVertical": 8,
}
}
>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 12,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
ANOTHER CAT
</Text>
</View>
<View
data={
Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "Highlighted!!!",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
viewabilityConfigCallbackPairs={Array []}
>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Just a channel
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
Object {
"color": "#ffffff",
},
]
}
>
Highlighted!!!
</Text>
</View>
</View>
</View>
</View>
</View>
</RCTScrollView>
`;

View file

@ -0,0 +1,127 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Category Body Component should match snapshot 1`] = `
<RCTScrollView
data={
Array [
Object {
"id": "1",
"name": "Just a channel",
},
Object {
"highlight": true,
"id": "2",
"name": "Highlighted!!!",
},
]
}
getItem={[Function]}
getItemCount={[Function]}
keyExtractor={[Function]}
onContentSizeChange={[Function]}
onLayout={[Function]}
onMomentumScrollBegin={[Function]}
onMomentumScrollEnd={[Function]}
onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
removeClippedSubviews={false}
renderItem={[Function]}
scrollEventThrottle={50}
stickyHeaderIndices={Array []}
viewabilityConfigCallbackPairs={Array []}
>
<View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Just a channel
</Text>
</View>
</View>
<View
onLayout={[Function]}
style={null}
>
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
Object {
"color": "#ffffff",
},
]
}
>
Highlighted!!!
</Text>
</View>
</View>
</View>
</RCTScrollView>
`;

View file

@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Category Channel List Item should match snapshot 1`] = `
<View
style={
Object {
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<Icon
name="globe"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "rgba(255,255,255,0.72)",
"marginTop": 1,
"paddingLeft": 12,
},
undefined,
]
}
>
Channel Name
</Text>
</View>
`;

View file

@ -0,0 +1,19 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import ChannelItem from './index';
test('Category Channel List Item should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<ChannelItem
icon={'globe'}
name='Channel Name'
/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,75 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
paddingVertical: 4,
flexDirection: 'row',
},
icon: {
fontSize: 24,
lineHeight: 28,
color: changeOpacity(theme.sidebarText, 0.72),
},
text: {
marginTop: 1,
color: changeOpacity(theme.sidebarText, 0.72),
paddingLeft: 12,
},
highlight: {
color: theme.sidebarText,
},
}));
const textStyle = StyleSheet.create({
bright: typography('Body', 200, 'SemiBold'),
regular: typography('Body', 200, 'Regular'),
});
type Props = {
unreadCount?: number;
highlight?: boolean;
name: string;
icon: string;
}
const ChannelListItem = (props: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const {unreadCount, highlight, name, icon} = props;
// Make it brighter if it's highlighted, or has unreads
const bright = highlight || (unreadCount && unreadCount > 0);
return (
<View style={styles.container}>
{icon && (
<CompassIcon
name={icon}
style={styles.icon}
/>
)}
<Text
style={[
bright ? textStyle.bright : textStyle.regular,
styles.text,
bright && styles.highlight,
]}
>
{name}
</Text>
</View>
);
};
export default ChannelListItem;

View file

@ -0,0 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import CategoryBody from './index';
const channels: TempoChannel[] = [
{id: '1', name: 'Just a channel'},
{id: '2', name: 'Highlighted!!!', highlight: true},
];
test('Category Body Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<CategoryBody channels={channels}/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,32 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {FlatList} from 'react-native';
import ChannelListItem from './channel';
const renderChannelItem = (data: { item: TempoChannel }) => {
return (
<ChannelListItem
icon={'globe'}
name={data.item.name}
highlight={data.item.highlight}
/>
);
};
type Props = {
channels: TempoChannel[];
};
const CategoryBody = (props: Props) => {
return (
<FlatList
data={props.channels}
renderItem={renderChannelItem}
/>
);
};
export default CategoryBody;

View file

@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Category Header Component should match snapshot 1`] = `
<View
style={
Object {
"marginTop": 12,
"paddingVertical": 8,
}
}
>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 12,
"fontWeight": "600",
"lineHeight": 16,
}
}
>
CAT HEADING
</Text>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Header from './index';
test('Category Header Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Header heading='Cat Heading'/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,39 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Text, View} from 'react-native';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
paddingVertical: 8,
marginTop: 12,
},
heading: {
color: changeOpacity(theme.sidebarText, 0.64),
...typography('Heading', 75),
},
}));
type Props = {
heading: string;
}
const CategoryHeader = (props: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
return (
<View style={styles.container}>
<Text style={styles.heading}>
{props.heading.toUpperCase()}
</Text>
</View>
);
};
export default CategoryHeader;

View file

@ -0,0 +1,26 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Category from './index';
const channels: TempoChannel[] = [
{id: '1', name: 'Just a channel'},
{id: '2', name: 'Highlighted!!!', highlight: true},
];
const categories: TempoCategory[] = [
{id: '1', title: 'My first Category', channels},
{id: '2', title: 'Another cat', channels},
];
test('Category List Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Category categories={categories}/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,40 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {FlatList, StyleSheet} from 'react-native';
import ThreadsButton from '../threads';
import CategoryBody from './body';
import CategoryHeader from './header';
type Props = {
categories: TempoCategory[];
}
const styles = StyleSheet.create({
flex: {
flex: 1,
},
});
const renderCategory = (data: {item: TempoCategory}) => (
<>
<CategoryHeader heading={data.item.title}/>
<CategoryBody channels={data.item.channels}/>
</>
);
const Categories = (props: Props) => {
return (
<FlatList
data={props.categories}
renderItem={renderCategory}
ListHeaderComponent={ThreadsButton}
style={styles.flex}
/>
);
};
export default Categories;

View file

@ -0,0 +1,137 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Channel List Header Component should match snapshot 1`] = `
<View>
<View
style={
Object {
"alignItems": "center",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<Text
style={
Object {
"color": "#ffffff",
"fontFamily": "Metropolis-SemiBold",
"fontSize": 28,
"fontWeight": "600",
"lineHeight": 36,
}
}
>
Hello World!
</Text>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"marginLeft": 4,
}
}
>
<Icon
name="chevron-down"
style={
Object {
"color": "rgba(255,255,255,0.8)",
"fontSize": 24,
}
}
/>
</View>
</View>
</View>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"alignItems": "center",
"backgroundColor": "rgba(255,255,255,0.08)",
"borderRadius": 14,
"height": 28,
"justifyContent": "center",
"width": 28,
}
}
>
<Icon
name="plus"
style={
Object {
"color": "rgba(255,255,255,0.8)",
"fontSize": 18,
}
}
/>
</View>
</View>
</View>
<Text
style={
Object {
"color": "rgba(255,255,255,0.64)",
"fontFamily": "OpenSans-SemiBold",
"fontSize": 11,
"fontWeight": "600",
"lineHeight": 16,
}
}
/>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Header from './index';
test('Channel List Header Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Header heading='Hello World!'/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,89 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Text, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
type Props = {
heading: string;
subheading?: string;
iconPad?: boolean;
}
const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({
headingStyles: {
color: theme.sidebarText,
...typography('Heading', 700),
},
subHeadingStyles: {
color: changeOpacity(theme.sidebarText, 0.64),
...typography('Heading', 50),
},
iconPad: {
marginLeft: 44,
},
headerRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
chevronButton: {
marginLeft: 4,
},
chevronIcon: {
color: changeOpacity(theme.sidebarText, 0.8),
fontSize: 24,
},
plusButton: {
backgroundColor: changeOpacity(theme.sidebarText, 0.08),
height: 28,
width: 28,
borderRadius: 14,
justifyContent: 'center',
alignItems: 'center',
},
plusIcon: {
color: changeOpacity(theme.sidebarText, 0.8),
fontSize: 18,
},
}));
const ChannelListHeader = (props: Props) => {
const theme = useTheme();
const styles = getStyles(theme);
return (
<View style={props.iconPad && styles.iconPad}>
<View style={styles.headerRow}>
<View style={styles.headerRow}>
<Text style={styles.headingStyles}>
{props.heading}
</Text>
<TouchableWithFeedback style={styles.chevronButton}>
<CompassIcon
style={styles.chevronIcon}
name={'chevron-down'}
/>
</TouchableWithFeedback>
</View>
<TouchableWithFeedback style={styles.plusButton}>
<CompassIcon
style={styles.plusIcon}
name={'plus'}
/>
</TouchableWithFeedback>
</View>
<Text style={styles.subHeadingStyles}>
{props.subheading}
</Text>
</View>
);
};
export default ChannelListHeader;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import ChannelsList from './index';
test('Channels List should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<ChannelsList/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,79 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useState} from 'react';
import {View} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
import TABLET from '@constants/view';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {makeStyleSheetFromTheme} from '@utils/theme';
import Categories from './categories';
import ChannelListHeader from './header';
import LoadingError from './loading_error';
import SearchField from './search';
// import Loading from './loading';
const channels: TempoChannel[] = [
{id: '1', name: 'Just a channel'},
{id: '2', name: 'A Highlighted Channel!!!', highlight: true},
{id: '3', name: 'And a longer channel name.'},
];
const categories: TempoCategory[] = [
{id: '1', title: 'My first Category', channels},
{id: '2', title: 'Another Cat', channels},
];
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
flex: 1,
backgroundColor: theme.sidebarBg,
paddingHorizontal: 20,
paddingVertical: 10,
},
maxW: {
maxWidth: TABLET.TABLET_SIDEBAR_WIDTH,
},
}));
type ChannelListProps = {
iconPad?: boolean;
}
const ChannelList = ({iconPad}: ChannelListProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
// @to-do; remove after testing
const [showCats, setShowCats] = useState<boolean>(true);
const isTablet = useIsTablet();
return (
<View style={[styles.container, isTablet && styles.maxW]}>
<TouchableOpacity onPress={() => setShowCats(!showCats)}>
<ChannelListHeader
heading='Contributors'
subheading='Community TEST'
iconPad={iconPad}
/>
</TouchableOpacity>
{showCats && (
<>
<SearchField/>
<Categories categories={categories}/>
</>
)}
{/* <Loading/> */}
{!showCats && (<LoadingError/>)}
</View>
);
};
export default ChannelList;

View file

@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Loading should match snapshot 1`] = `
<View
style={
Object {
"flex": 1,
"justifyContent": "center",
"maxHeight": 40,
"padding": 20,
}
}
>
<View
style={
Array [
Object {
"aspectRatio": 1,
},
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
undefined,
]
}
>
<View
autoPlay={true}
cacheComposition={true}
collapsable={false}
enableMergePathsAndroidForKitKatAndAbove={false}
forwardedRef={[Function]}
loop={true}
nativeID="animatedComponent"
onAnimationFinish={[Function]}
onLayout={[Function]}
progress={0}
resizeMode="contain"
sourceJson="{\\"v\\":\\"5.5.7\\",\\"meta\\":{\\"g\\":\\"LottieFiles AE 0.1.20\\",\\"a\\":\\"\\",\\"k\\":\\"\\",\\"d\\":\\"\\",\\"tc\\":\\"\\"},\\"fr\\":60,\\"ip\\":0,\\"op\\":40,\\"w\\":32,\\"h\\":32,\\"nm\\":\\"Spinner - white\\",\\"ddd\\":0,\\"assets\\":[],\\"layers\\":[{\\"ddd\\":0,\\"ind\\":1,\\"ty\\":4,\\"nm\\":\\"Shape Layer 2\\",\\"sr\\":1,\\"ks\\":{\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":11},\\"r\\":{\\"a\\":1,\\"k\\":[{\\"i\\":{\\"x\\":[0.833],\\"y\\":[0.833]},\\"o\\":{\\"x\\":[0.167],\\"y\\":[0.167]},\\"t\\":0,\\"s\\":[0]},{\\"t\\":40,\\"s\\":[360]}],\\"ix\\":10},\\"p\\":{\\"a\\":0,\\"k\\":[16,16,0],\\"ix\\":2},\\"a\\":{\\"a\\":0,\\"k\\":[0,0,0],\\"ix\\":1},\\"s\\":{\\"a\\":0,\\"k\\":[100,100,100],\\"ix\\":6}},\\"ao\\":0,\\"shapes\\":[{\\"ty\\":\\"gr\\",\\"it\\":[{\\"d\\":1,\\"ty\\":\\"el\\",\\"s\\":{\\"a\\":0,\\"k\\":[27,27],\\"ix\\":2},\\"p\\":{\\"a\\":0,\\"k\\":[0,0],\\"ix\\":3},\\"nm\\":\\"Ellipse Path 1\\",\\"mn\\":\\"ADBE Vector Shape - Ellipse\\",\\"hd\\":false},{\\"ty\\":\\"gs\\",\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":9},\\"w\\":{\\"a\\":0,\\"k\\":3,\\"ix\\":10},\\"g\\":{\\"p\\":3,\\"k\\":{\\"a\\":0,\\"k\\":[0.001,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.5,1,0],\\"ix\\":8}},\\"s\\":{\\"a\\":0,\\"k\\":[2.423,11.896],\\"ix\\":4},\\"e\\":{\\"a\\":0,\\"k\\":[1.431,-12.387],\\"ix\\":5},\\"t\\":1,\\"lc\\":1,\\"lj\\":1,\\"ml\\":4,\\"ml2\\":{\\"a\\":0,\\"k\\":4,\\"ix\\":13},\\"bm\\":0,\\"nm\\":\\"Gradient Stroke 1\\",\\"mn\\":\\"ADBE Vector Graphic - G-Stroke\\",\\"hd\\":false},{\\"ty\\":\\"tr\\",\\"p\\":{\\"a\\":0,\\"k\\":[0.05,0],\\"ix\\":2},\\"a\\":{\\"a\\":0,\\"k\\":[0,0],\\"ix\\":1},\\"s\\":{\\"a\\":0,\\"k\\":[100,100],\\"ix\\":3},\\"r\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":6},\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":7},\\"sk\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":4},\\"sa\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":5},\\"nm\\":\\"Transform\\"}],\\"nm\\":\\"Ellipse 1\\",\\"np\\":3,\\"cix\\":2,\\"bm\\":0,\\"ix\\":1,\\"mn\\":\\"ADBE Vector Group\\",\\"hd\\":false}],\\"ip\\":0,\\"op\\":1800,\\"st\\":0,\\"bm\\":0},{\\"ddd\\":0,\\"ind\\":2,\\"ty\\":4,\\"nm\\":\\"Shape Layer 1\\",\\"parent\\":1,\\"sr\\":1,\\"ks\\":{\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":11},\\"r\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":10},\\"p\\":{\\"a\\":0,\\"k\\":[0,0,0],\\"ix\\":2},\\"a\\":{\\"a\\":0,\\"k\\":[0,0,0],\\"ix\\":1},\\"s\\":{\\"a\\":0,\\"k\\":[100,100,100],\\"ix\\":6}},\\"ao\\":0,\\"hasMask\\":true,\\"masksProperties\\":[{\\"inv\\":false,\\"mode\\":\\"a\\",\\"pt\\":{\\"a\\":0,\\"k\\":{\\"i\\":[[0,0],[0,0],[0,0],[0,0]],\\"o\\":[[0,0],[0,0],[0,0],[0,0]],\\"v\\":[[-15.95,-15.938],[-15.963,16],[-0.025,16],[-0.013,-15.938]],\\"c\\":true},\\"ix\\":1},\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":3},\\"x\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":4},\\"nm\\":\\"Mask 1\\"}],\\"shapes\\":[{\\"ty\\":\\"gr\\",\\"it\\":[{\\"d\\":1,\\"ty\\":\\"el\\",\\"s\\":{\\"a\\":0,\\"k\\":[27,27],\\"ix\\":2},\\"p\\":{\\"a\\":0,\\"k\\":[0,0],\\"ix\\":3},\\"nm\\":\\"Ellipse Path 1\\",\\"mn\\":\\"ADBE Vector Shape - Ellipse\\",\\"hd\\":false},{\\"ty\\":\\"st\\",\\"c\\":{\\"a\\":0,\\"k\\":[1,1,1,1],\\"ix\\":3},\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":4},\\"w\\":{\\"a\\":0,\\"k\\":3,\\"ix\\":5},\\"lc\\":1,\\"lj\\":1,\\"ml\\":4,\\"bm\\":0,\\"nm\\":\\"Stroke 1\\",\\"mn\\":\\"ADBE Vector Graphic - Stroke\\",\\"hd\\":false},{\\"ty\\":\\"tr\\",\\"p\\":{\\"a\\":0,\\"k\\":[0.05,0],\\"ix\\":2},\\"a\\":{\\"a\\":0,\\"k\\":[0,0],\\"ix\\":1},\\"s\\":{\\"a\\":0,\\"k\\":[100,100],\\"ix\\":3},\\"r\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":6},\\"o\\":{\\"a\\":0,\\"k\\":100,\\"ix\\":7},\\"sk\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":4},\\"sa\\":{\\"a\\":0,\\"k\\":0,\\"ix\\":5},\\"nm\\":\\"Transform\\"}],\\"nm\\":\\"Ellipse 1\\",\\"np\\":3,\\"cix\\":2,\\"bm\\":0,\\"ix\\":1,\\"mn\\":\\"ADBE Vector Group\\",\\"hd\\":false}],\\"ip\\":0,\\"op\\":1800,\\"st\\":0,\\"bm\\":0}],\\"markers\\":[]}"
speed={1}
style={
Object {
"aspectRatio": 1,
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
</View>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Loading from './index';
test('Loading should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Loading/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,31 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import LottieView from 'lottie-react-native';
import React from 'react';
import {StyleSheet, View} from 'react-native';
const Loading = () => (
<View style={styles.container}>
<LottieView
source={require('./spinner.json')}
autoPlay={true}
loop={true}
/>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
maxHeight: 40,
},
lottie: {
height: 32,
width: 32,
},
});
export default Loading;

View file

@ -0,0 +1 @@
{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":40,"w":32,"h":32,"nm":"Spinner - white","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":40,"s":[360]}],"ix":10},"p":{"a":0,"k":[16,16,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[27,27],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":3,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0.001,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.5,1,0],"ix":8}},"s":{"a":0,"k":[2.423,11.896],"ix":4},"e":{"a":0,"k":[1.431,-12.387],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":13},"bm":0,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.05,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-15.95,-15.938],[-15.963,16],[-0.025,16],[-0.013,-15.938]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[27,27],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.05,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0}],"markers":[]}

View file

@ -0,0 +1,151 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Loading Error should match snapshot 1`] = `
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"justifyContent": "center",
"padding": 20,
}
}
>
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "rgba(255,255,255,0.08)",
"borderRadius": 60,
"height": 120,
"justifyContent": "center",
"width": 120,
}
}
>
<Icon
name="alert-circle-outline"
style={
Object {
"color": "rgba(255,255,255,0.48)",
"fontSize": 72,
"lineHeight": 72,
}
}
/>
</View>
<Text
style={
Array [
Object {
"fontFamily": "Metropolis-SemiBold",
"fontSize": 20,
"fontWeight": "600",
"lineHeight": 28,
},
Object {
"color": "#ffffff",
"marginTop": 20,
"textAlign": "center",
},
]
}
>
Couldnt load Staff
</Text>
<Text
style={
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"color": "#ffffff",
"marginTop": 4,
"textAlign": "center",
},
]
}
>
There was a problem loading the content for this team.
</Text>
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"marginTop": 24,
},
Array [
Object {
"alignItems": "center",
"borderRadius": 4,
"flex": 0,
"justifyContent": "center",
"textAlignVertical": "center",
},
Object {
"height": 48,
"paddingHorizontal": 24,
"paddingVertical": 14,
},
Object {
"backgroundColor": "#ffffff",
},
],
]
}
>
<Text
style={
Array [
Object {
"alignItems": "center",
"fontFamily": "OpenSans-SemiBold",
"fontWeight": "600",
"justifyContent": "center",
"padding": 1,
"textAlignVertical": "center",
},
Object {
"fontSize": 16,
"lineHeight": 18,
"marginTop": 2,
},
Object {
"color": "#1c58d9",
},
]
}
>
Retry
</Text>
</View>
</View>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import ErrorComponent from './index';
test('Loading Error should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<ErrorComponent/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,70 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Text, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import {useTheme} from '@context/theme';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
iconWrapper: {
height: 120,
width: 120,
backgroundColor: changeOpacity(theme.sidebarText, 0.08),
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
},
icon: {
fontSize: 72,
lineHeight: 72,
color: changeOpacity(theme.sidebarText, 0.48),
},
header: {
color: theme.sidebarHeaderTextColor,
marginTop: 20,
textAlign: 'center',
},
body: {
color: theme.sidebarText,
textAlign: 'center',
marginTop: 4,
},
}));
const LoadingError = () => {
const theme = useTheme();
const styles = getStyleSheet(theme);
return (
<View style={styles.container}>
<View style={styles.iconWrapper}>
<CompassIcon
name='alert-circle-outline'
style={styles.icon}
/>
</View>
<Text style={[typography('Heading', 400), styles.header]}>
{'Couldnt load Staff'}
</Text>
<Text style={[typography('Body', 200), styles.body]}>
{'There was a problem loading the content for this team.'}
</Text>
<TouchableWithFeedback style={[{marginTop: 24}, buttonBackgroundStyle(theme, 'lg', 'primary', 'inverted')]}>
<Text style={buttonTextStyle(theme, 'lg', 'primary', 'inverted')}>{'Retry'}</Text>
</TouchableWithFeedback>
</View>
);
};
export default LoadingError;

View file

@ -0,0 +1,63 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Search Field should match snapshot 1`] = `
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "rgba(255,255,255,0.12)",
"borderRadius": 8,
"flex": 1,
"flexDirection": "row",
"height": 40,
"justifyContent": "flex-start",
"marginVertical": 20,
"maxHeight": 40,
"padding": 8,
"width": "100%",
}
}
>
<Icon
name="magnify"
style={
Object {
"color": "rgba(255,255,255,0.72)",
"fontSize": 24,
"width": 24,
}
}
/>
<TextInput
collapsable={false}
onGestureHandlerEvent={[Function]}
onGestureHandlerStateChange={[Function]}
placeholder="Find Channels"
placeholderTextColor="rgba(255,255,255,0.72)"
style={
Array [
Array [
Object {
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
Object {
"textAlignVertical": "center",
},
],
Object {
"alignContent": "center",
"alignItems": "center",
"color": "#ffffff",
"flex": 1,
"height": 40,
"marginLeft": 5,
"marginTop": -2,
},
]
}
/>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Search from './index';
test('Search Field should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Search/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,69 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {StyleSheet, View} from 'react-native';
import {TextInput} from 'react-native-gesture-handler';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
width: '100%',
backgroundColor: changeOpacity(theme.sidebarText, 0.12),
borderRadius: 8,
padding: 8,
marginVertical: 20,
height: 40,
maxHeight: 40,
},
icon: {
width: 24,
fontSize: 24,
color: changeOpacity(theme.sidebarText, 0.72),
},
input: {
flex: 1,
height: 40,
color: theme.sidebarText,
alignItems: 'center',
alignContent: 'center',
marginLeft: 5,
marginTop: -2,
},
}));
const textStyles = StyleSheet.create([
typography('Body', 200),
{textAlignVertical: 'center'},
]);
const SearchField = () => {
const theme = useTheme();
const styles = getStyleSheet(theme);
return (
<View
style={styles.container}
>
<CompassIcon
name='magnify'
style={styles.icon}
/>
<TextInput
style={[textStyles, styles.input]}
placeholder='Find Channels'
placeholderTextColor={changeOpacity(theme.sidebarText, 0.72)}
/>
</View>
);
};
export default SearchField;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// THIS IS TEMPORARY POC/MVP - WILL BE REMOVEd
// @to-do - Wire up actual models
type TempoChannel = {
id: string;
name: string;
highlight?: boolean;
};
type TempoCategory = {
id: string;
title: string;
channels: TempoChannel[];
}

View file

@ -0,0 +1,70 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Threads Component should match snapshot 1`] = `
<View
onMoveShouldSetResponder={[Function]}
onMoveShouldSetResponderCapture={[Function]}
onResponderEnd={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderReject={[Function]}
onResponderRelease={[Function]}
onResponderStart={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onStartShouldSetResponderCapture={[Function]}
>
<View
accessible={true}
focusable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View
style={
Object {
"display": "flex",
"flexDirection": "row",
}
}
>
<Icon
name="message-text-outline"
style={
Object {
"color": "#ffffff",
"fontSize": 24,
"lineHeight": 28,
}
}
/>
<Text
style={
Array [
Array [
Object {
"fontFamily": "OpenSans-SemiBold",
"fontSize": 16,
"fontWeight": "600",
"lineHeight": 24,
},
],
Object {
"color": "#ffffff",
"paddingLeft": 12,
},
]
}
>
Threads
</Text>
</View>
</View>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Threads from './index';
test('Threads Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Threads/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import {Screens} from '@constants';
import {useTheme} from '@context/theme';
import {goToScreen} from '@screens/navigation';
import {makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
display: 'flex',
flexDirection: 'row',
},
icon: {
fontSize: 24,
lineHeight: 28,
color: theme.sidebarText,
},
text: {
color: theme.sidebarText,
paddingLeft: 12,
},
}));
const textStyle = StyleSheet.create([typography('Body', 200, 'SemiBold')]);
const ThreadsButton = () => {
const theme = useTheme();
const styles = getStyleSheet(theme);
/*
* @to-do:
* - Check if there are threads, else return null
* - Change to button, navigate to threads view
* - Add right-side number badge
*/
return (
<TouchableWithFeedback onPress={() => goToScreen(Screens.CHANNEL, 'Channel', {}, {topBar: {visible: false}})} >
<View style={styles.container}>
<CompassIcon
name='message-text-outline'
style={styles.icon}
/>
<Text style={[textStyle, styles.text]}>{'Threads'}</Text>
</View>
</TouchableWithFeedback>
);
};
export default ThreadsButton;

View file

@ -5,4 +5,7 @@ import {createIconSetFromFontello} from 'react-native-vector-icons';
import fontelloConfig from '@assets/compass-icons.json';
export default createIconSetFromFontello(fontelloConfig, 'compass-icons', 'compass-icons.ttf');
const CompassIcon = createIconSetFromFontello(fontelloConfig, 'compass-icons',
'compass-icons.ttf');
export default CompassIcon;

View file

@ -5,9 +5,9 @@ import React from 'react';
import {ListRenderItemInfo, View} from 'react-native';
import {FlatList} from 'react-native-gesture-handler';
import {makeStyleSheetFromTheme} from '@app/utils/theme';
import FormattedText from '@components/formatted_text';
import {useTheme} from '@context/theme';
import {makeStyleSheetFromTheme} from '@utils/theme';
import TeamListItem from './team_list_item';

View file

@ -7,9 +7,9 @@ import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {Permissions} from '@app/constants';
import {hasPermission} from '@app/utils/role';
import {Permissions} from '@constants';
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
import {hasPermission} from '@utils/role';
import TeamSidebar from './team_sidebar';

View file

@ -1,38 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
// TODO PLACEHOLDER
export default function ServerIcon() {
const theme = useTheme();
const styles = getStyleSheet(theme);
return (
<View style={styles.container}>
<CompassIcon
size={24}
name='server-variant'
color={changeOpacity(theme.buttonColor, 0.56)}
/>
</View>
);
}
const getStyleSheet = makeStyleSheetFromTheme(() => {
return {
container: {
flex: 0,
borderRadius: 10,
height: 60,
width: '100%',
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
},
};
});

View file

@ -11,7 +11,6 @@ import {useTheme} from '@context/theme';
import {makeStyleSheetFromTheme} from '@utils/theme';
import AddTeam from './add_team/add_team';
import ServerIcon from './server_icon/server_icon';
import TeamList from './team_list';
import type TeamModel from '@typings/database/models/servers/team';
@ -19,9 +18,10 @@ import type TeamModel from '@typings/database/models/servers/team';
type Props = {
canCreateTeams: boolean;
otherTeams: TeamModel[];
iconPad?: boolean;
}
export default function TeamSidebar({canCreateTeams, otherTeams}: Props) {
export default function TeamSidebar({canCreateTeams, otherTeams, iconPad}: Props) {
const theme = useTheme();
const styles = getStyleSheet(theme);
const serverUrl = useServerUrl();
@ -34,8 +34,7 @@ export default function TeamSidebar({canCreateTeams, otherTeams}: Props) {
return (
<View style={styles.container}>
<ServerIcon/>
<View style={styles.listContainer}>
<View style={[styles.listContainer, iconPad && styles.iconMargin]}>
<TeamList/>
{showAddTeam && (
<AddTeam
@ -55,11 +54,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
height: '100%',
backgroundColor: theme.sidebarBg,
display: 'flex',
paddingTop: 10,
},
listContainer: {
backgroundColor: theme.sidebarTeamBarBg,
borderTopRightRadius: 12,
flex: 1,
},
iconMargin: {
marginTop: 44,
paddingTop: 0,
},
};
});

View file

@ -16,7 +16,6 @@ import {
import {markChannelAsViewed} from '@actions/local/channel';
import {backgroundNotification, openNotification} from '@actions/remote/notifications';
import EphemeralStore from '@app/store/ephemeral_store';
import {Device, Events, Navigation, Screens} from '@constants';
import {GLOBAL_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
@ -25,6 +24,7 @@ import NativeNotifications from '@notifications';
import {queryServerName} from '@queries/app/servers';
import {queryCurrentChannelId} from '@queries/servers/system';
import {showOverlay} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {isTablet} from '@utils/helpers';
import {convertToNotificationData} from '@utils/notification';

View file

@ -7,11 +7,11 @@ import {AppState, AppStateStatus} from 'react-native';
import {setCurrentUserStatusOffline} from '@actions/local/user';
import {fetchStatusByIds} from '@actions/remote/user';
import {handleClose, handleEvent, handleFirstConnect, handleReconnect} from '@actions/websocket';
import WebSocketClient from '@app/client/websocket';
import {General} from '@app/constants';
import {queryCurrentUserId, resetWebSocketLastDisconnected} from '@app/queries/servers/system';
import {queryAllUsers} from '@app/queries/servers/user';
import WebSocketClient from '@client/websocket';
import {General} from '@constants';
import DatabaseManager from '@database/manager';
import {queryCurrentUserId, resetWebSocketLastDisconnected} from '@queries/servers/system';
import {queryAllUsers} from '@queries/servers/user';
import type {ServerCredential} from '@typings/credentials';

View file

@ -8,12 +8,12 @@ import {Navigation as RNN} from 'react-native-navigation';
import Animated from 'react-native-reanimated';
import RNBottomSheet from 'reanimated-bottom-sheet';
import {changeOpacity, makeStyleSheetFromTheme} from '@app/utils/theme';
import {Navigation} from '@constants';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {dismissModal} from '@screens/navigation';
import {hapticFeedback} from '@utils/general';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import Indicator from './indicator';

View file

@ -1,48 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Text, View} from 'react-native';
import {makeStyleSheetFromTheme} from '@utils/theme';
type ChannelProps = {
theme: Theme;
}
const ChannelList = ({theme}: ChannelProps) => {
const styles = getStyleSheet(theme);
return (
<View
testID='channel.screen'
style={styles.container}
>
<Text style={styles.screenTitle}>{' Channel Screen '}</Text>
</View>
);
};
const getStyleSheet = makeStyleSheetFromTheme(() => ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ffffff',
},
tabContainer: {
position: 'absolute',
bottom: 0,
backgroundColor: '#ffffff',
},
textContainer: {
marginTop: 30,
alignItems: 'center',
},
screenTitle: {
fontSize: 30,
alignSelf: 'center',
},
}));
export default ChannelList;

View file

@ -5,7 +5,7 @@ import React, {useCallback, useEffect} from 'react';
import {Keyboard} from 'react-native';
import {Navigation} from 'react-native-navigation';
import EmojiPicker from '@app/components/emoji_picker';
import EmojiPicker from '@components/emoji_picker';
import {dismissModal, setButtons} from '@screens/navigation';
type Props = {

View file

@ -6,13 +6,13 @@ import {useIntl} from 'react-intl';
import {DeviceEventEmitter, TextStyle} from 'react-native';
import {setStatus} from '@actions/remote/user';
import {useServerUrl} from '@app/context/server_url';
import DrawerItem from '@components/drawer_item';
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
import StatusLabel from '@components/status_label';
import UserStatusIndicator from '@components/user_status';
import {Navigation} from '@constants';
import General from '@constants/general';
import {useServerUrl} from '@context/server_url';
import {bottomSheet, dismissModal} from '@screens/navigation';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity} from '@utils/theme';

View file

@ -3,16 +3,16 @@
import {useIsFocused, useRoute} from '@react-navigation/native';
import React from 'react';
import {Text, View} from 'react-native';
import {View} from 'react-native';
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import ChannelList from '@components/channel_list';
import TeamSidebar from '@components/team_sidebar';
import {View as ViewConstants} from '@constants';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import Channel from '@screens/channel';
import {goToScreen} from '@screens/navigation';
import ServerIcon from '@screens/home/channel_list/server_icon/server_icon';
import {makeStyleSheetFromTheme} from '@utils/theme';
import type {LaunchProps} from '@typings/launch';
@ -43,18 +43,13 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
const ChannelListScreen = (props: ChannelProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const isTablet = useIsTablet();
const route = useRoute();
const isFocused = useIsFocused();
const insets = useSafeAreaInsets();
const params = route.params as {direction: string};
let tabletSidebarStyle;
if (isTablet) {
const {TABLET_SIDEBAR_WIDTH, TEAM_SIDEBAR_WIDTH} = ViewConstants;
tabletSidebarStyle = {maxWidth: (TABLET_SIDEBAR_WIDTH - TEAM_SIDEBAR_WIDTH)};
}
const animated = useAnimatedStyle(() => {
if (!isFocused) {
let initial = 0;
@ -79,18 +74,15 @@ const ChannelListScreen = (props: ChannelProps) => {
style={styles.content}
edges={['bottom', 'left', 'right']}
>
<ServerIcon/>
<Animated.View
style={[styles.content, animated]}
>
<TeamSidebar/>
<View style={[styles.flex, {alignItems: 'center', justifyContent: 'center'}, tabletSidebarStyle]}>
<Text
onPress={() => goToScreen('Channel', '', undefined, {topBar: {visible: false}})}
style={{fontSize: 20, color: theme.centerChannelColor}}
>
{'Channel List'}
</Text>
</View>
{/* @to-do: Server Icon requires padding in the team and channel components:
* https://mattermost.atlassian.net/browse/MM-39702
*/}
<TeamSidebar iconPad={true}/>
<ChannelList iconPad={false}/>
{isTablet &&
<Channel {...props}/>
}

View file

@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Server Icon Component should match snapshot 1`] = `
<View
style={
Object {
"alignItems": "center",
"flex": 0,
"height": 40,
"justifyContent": "center",
"left": 16,
"overflow": "hidden",
"position": "absolute",
"top": 10,
"width": 40,
"zIndex": 10,
}
}
>
<Icon
color="rgba(255,255,255,0.56)"
name="server-variant"
size={24}
/>
</View>
`;

View file

@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import Icon from './server_icon';
test('Server Icon Component should match snapshot', () => {
const {toJSON} = renderWithIntlAndTheme(
<Icon/>,
);
expect(toJSON()).toMatchSnapshot();
});

View file

@ -0,0 +1,39 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {StyleSheet, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {changeOpacity} from '@utils/theme';
const styles = StyleSheet.create({
icon: {
flex: 0,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
zIndex: 10,
top: 10,
left: 16,
width: 40,
height: 40,
},
});
export default function ServerIcon() {
const theme = useTheme();
return (
<View style={styles.icon}>
<CompassIcon
size={24}
name='server-variant'
color={changeOpacity(theme.buttonColor, 0.56)}
/>
</View>
);
}

View file

@ -7,8 +7,8 @@ import {ActivityIndicator, Platform, useWindowDimensions, View} from 'react-nati
import Button from 'react-native-button';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import FormattedText from '@app/components/formatted_text';
import FloatingTextInput, {FloatingTextInputRef} from '@components/floating_text_input_label';
import FormattedText from '@components/formatted_text';
import {useIsTablet} from '@hooks/device';
import {t} from '@i18n';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';

View file

@ -4,7 +4,7 @@
import React from 'react';
import {View} from 'react-native';
import FormattedText from '@app/components/formatted_text';
import FormattedText from '@components/formatted_text';
import {useIsTablet} from '@hooks/device';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';

View file

@ -44,6 +44,7 @@ export const buttonBackgroundStyle = (
flex: 0,
alignItems: 'center',
justifyContent: 'center',
textAlignVertical: 'center',
borderRadius: 4,
},
fullWidth: {
@ -106,13 +107,13 @@ export const buttonBackgroundStyle = (
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
},
hover: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0),
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
},
active: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0),
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
},
focus: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0),
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
},
},
},
@ -392,6 +393,10 @@ export const buttonTextStyle = (
main: {
fontFamily: 'OpenSans-SemiBold',
fontWeight: '600',
textAlignVertical: 'center',
alignItems: 'center',
justifyContent: 'center',
padding: 1,
},
underline: {
textDecorationLine: 'underline',
@ -403,18 +408,22 @@ export const buttonTextStyle = (
fontSize: 11,
lineHeight: 10,
letterSpacing: 0.02,
marginTop: 2,
},
s: {
fontSize: 12,
lineHeight: 11,
lineHeight: 12,
marginTop: 1,
},
m: {
fontSize: 14,
lineHeight: 14,
marginTop: 3,
},
lg: {
fontSize: 16,
lineHeight: 18,
marginTop: 2,
},
});

View file

@ -40,9 +40,13 @@ PODS:
- libwebp/webp (= 1.2.0)
- libwebp/demux (1.2.0):
- libwebp/webp
- libwebp/mux (1.2.0):
- libwebp/mux (1.2.1):
- libwebp/demux
- libwebp/webp (1.2.0)
- libwebp/webp (1.2.1)
- lottie-ios (3.2.3)
- lottie-react-native (4.1.3):
- lottie-ios (~> 3.2.3)
- React-Core
- Permission-Camera (3.1.0):
- RNPermissions
- Permission-PhotoLibrary (3.1.0):
@ -479,7 +483,7 @@ PODS:
- React-jsi
- XCDYouTubeKit (2.8.2)
- Yoga (1.14.0)
- YoutubePlayer-in-WKWebView (0.3.5)
- YoutubePlayer-in-WKWebView (0.3.8)
DEPENDENCIES:
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
@ -494,6 +498,8 @@ DEPENDENCIES:
- hermes-engine (~> 0.9.0)
- jail-monkey (from `../node_modules/jail-monkey`)
- libevent (~> 2.1.12)
- lottie-ios (from `../node_modules/lottie-ios`)
- lottie-react-native (from `../node_modules/lottie-react-native`)
- Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`)
- Permission-PhotoLibrary (from `../node_modules/react-native-permissions/ios/PhotoLibrary`)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
@ -609,6 +615,10 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
jail-monkey:
:path: "../node_modules/jail-monkey"
lottie-ios:
:path: "../node_modules/lottie-ios"
lottie-react-native:
:path: "../node_modules/lottie-react-native"
Permission-Camera:
:path: "../node_modules/react-native-permissions/ios/Camera"
Permission-PhotoLibrary:
@ -777,6 +787,8 @@ SPEC CHECKSUMS:
jail-monkey: 07b83767601a373db876e939b8dbf3f5eb15f073
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: e90b9c01d99205d03b6bb8f2c8c415e5a4ef66f0
lottie-ios: c058aeafa76daa4cf64d773554bccc8385d0150e
lottie-react-native: b561920bba7ec727ec94a473b683cffba00faece
Permission-Camera: 0db4fd6e1c556c1cf47f38b989a8084cea3ec3dd
Permission-PhotoLibrary: 9dcf80d1353d81b9f1e210c34291591236aaf2b6
RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9
@ -856,7 +868,7 @@ SPEC CHECKSUMS:
WatermelonDB: e043b1a32ddc63864eb539b562e86ef80f8224cd
XCDYouTubeKit: 79baadb0560673a67c771eba45f83e353fd12c1f
Yoga: 2b4a01651f42a32f82e6cef3830a3ba48088237f
YoutubePlayer-in-WKWebView: cfbf46da51d7370662a695a8f351e5fa1d3e1008
YoutubePlayer-in-WKWebView: 4fca3b4f6f09940077bfbae7bddb771f2b43aacd
PODFILE CHECKSUM: 7d223db07581157903686d5b376c1b697a056354

69
package-lock.json generated
View file

@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
"name": "mattermost-mobile",
"version": "2.0.0",
"hasInstallScript": true,
"license": "Apache 2.0",
@ -41,6 +42,8 @@
"emoji-regex": "10.0.0",
"fuse.js": "6.4.6",
"jail-monkey": "2.6.0",
"lottie-ios": "3.2.3",
"lottie-react-native": "4.1.3",
"mime-db": "1.50.0",
"moment-timezone": "0.5.33",
"prop-types": "15.7.2",
@ -15875,6 +15878,42 @@
"loose-envify": "cli.js"
}
},
"node_modules/lottie-ios": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
},
"node_modules/lottie-react-native": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-4.1.3.tgz",
"integrity": "sha512-RgQrn1VYRXMV3YTZE9DgZy/UqNsMmZvzXBU4eEUWDOTY9cemOoWmCg2BHrL7nNtDJqtsu1Mi/6e8hp0yN2mcBA==",
"dependencies": {
"invariant": "^2.2.2",
"prop-types": "^15.5.10",
"react-native-safe-modules": "^1.0.3"
},
"peerDependencies": {
"lottie-ios": "^3.2.3",
"react": "*",
"react-native": ">=0.46"
}
},
"node_modules/lottie-react-native/node_modules/dedent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz",
"integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s="
},
"node_modules/lottie-react-native/node_modules/react-native-safe-modules": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-native-safe-modules/-/react-native-safe-modules-1.0.3.tgz",
"integrity": "sha512-DUxti4Z+AgJ/ZsO5U7p3uSCUBko8JT8GvFlCeOXk9bMd+4qjpoDvMYpfbixXKgL88M+HwmU/KI1YFN6gsQZyBA==",
"dependencies": {
"dedent": "^0.6.0"
},
"peerDependencies": {
"react-native": "*"
}
},
"node_modules/lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@ -37342,6 +37381,36 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lottie-ios": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
},
"lottie-react-native": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-4.1.3.tgz",
"integrity": "sha512-RgQrn1VYRXMV3YTZE9DgZy/UqNsMmZvzXBU4eEUWDOTY9cemOoWmCg2BHrL7nNtDJqtsu1Mi/6e8hp0yN2mcBA==",
"requires": {
"invariant": "^2.2.2",
"prop-types": "^15.5.10",
"react-native-safe-modules": "^1.0.3"
},
"dependencies": {
"dedent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz",
"integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s="
},
"react-native-safe-modules": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-native-safe-modules/-/react-native-safe-modules-1.0.3.tgz",
"integrity": "sha512-DUxti4Z+AgJ/ZsO5U7p3uSCUBko8JT8GvFlCeOXk9bMd+4qjpoDvMYpfbixXKgL88M+HwmU/KI1YFN6gsQZyBA==",
"requires": {
"dedent": "^0.6.0"
}
}
}
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",

View file

@ -39,6 +39,8 @@
"emoji-regex": "10.0.0",
"fuse.js": "6.4.6",
"jail-monkey": "2.6.0",
"lottie-ios": "3.2.3",
"lottie-react-native": "4.1.3",
"mime-db": "1.50.0",
"moment-timezone": "0.5.33",
"prop-types": "15.7.2",