diff --git a/App.js b/App.js
index 4733a2a..9973224 100644
--- a/App.js
+++ b/App.js
@@ -1,5 +1,6 @@
import * as eva from "@eva-design/eva";
+import { Appearance, AppearanceProvider } from "react-native-appearance";
import { ApplicationProvider, IconRegistry } from "@ui-kitten/components";
import { AppLoading } from "expo";
@@ -20,14 +21,24 @@ class App extends React.Component {
this.state = {
authToken: null,
- isReady: false
+ isReady: false,
+ systemColorScheme: Appearance.getColorScheme()
};
}
async componentDidMount() {
const authToken = await AsyncStorage.getItem("authToken");
-
this.setState({ authToken, isReady: true });
+
+ this.appearanceListener = Appearance.addChangeListener(({ colorScheme }) => {
+ this.setState({ systemColorScheme: colorScheme });
+ });
+ }
+
+ componentWillUnmount() {
+ if (this.appearanceListener) {
+ this.appearanceListener.remove();
+ }
}
handleAuthTokenUpdate(authToken) {
@@ -42,32 +53,34 @@ class App extends React.Component {
}
return (
-
-
-
-
- {this.state.authToken ? (
- <>
-
+
+
+
+
+
+ {this.state.authToken ? (
+ <>
+
+ ({ title: route.params.subject })}
+ />
+ >
+ ) : (
({ title: route.params.subject })}
+ name="Sign In"
+ component={SignIn}
+ initialParams={{ onAuthTokenUpdate: this.handleAuthTokenUpdate.bind(this) }}
/>
- >
- ) : (
-
- )}
-
-
+ )}
+
+
+
);
}
diff --git a/app.json b/app.json
index d41c424..c125d58 100644
--- a/app.json
+++ b/app.json
@@ -23,6 +23,7 @@
],
"ios": {
"supportsTablet": true
- }
+ },
+ "userInterfaceStyle": "automatic"
}
}
diff --git a/components/account/SignIn.js b/components/account/SignIn.js
index 348f312..004df45 100644
--- a/components/account/SignIn.js
+++ b/components/account/SignIn.js
@@ -1,10 +1,12 @@
-import { Button, Input, Layout, Text } from "@ui-kitten/components";
+import { Button, Input, Layout, Text, useStyleSheet } from "@ui-kitten/components";
import React, { useState } from "react";
import { createZimbraClient } from "../../utils";
-import styles from "../../styles";
+import themedStyles from "../../styles";
function SignIn({ route }) {
+ const styles = useStyleSheet(themedStyles);
+
const [username, setUsername] = useState(null);
const [password, setPassword] = useState(null);
const [errorMessage, setErrorMessage] = useState(null);
diff --git a/components/conversation/Detail.js b/components/conversation/Detail.js
index a0338e8..14c2f90 100644
--- a/components/conversation/Detail.js
+++ b/components/conversation/Detail.js
@@ -1,12 +1,28 @@
-import { Divider, Icon, ListItem, TopNavigation, TopNavigationAction } from "@ui-kitten/components";
-import { SafeAreaView, Text } from "react-native";
+import { Divider, Icon, TopNavigation, TopNavigationAction, useStyleSheet } from "@ui-kitten/components";
+import LoadingScreen from "../shared/LoadingScreen";
import MessageList from "../message/List";
import React from "react";
+import { SafeAreaView } from "react-native";
+import Subject from "./DetailSubject";
import { createZimbraClient } from "../../utils";
+import themedStyles from "../../styles";
import useSWR from "swr";
+const BackIcon = (props) => ;
+const TrashIcon = (props) => ;
+const ArchiveIcon = (props) => ;
+
+const RightActions = () => (
+ <>
+
+
+ >
+);
+
function ConversationDetail({ navigation, route }) {
+ const styles = useStyleSheet(themedStyles);
+
async function fetcher(_key, id) {
return (await createZimbraClient()).getConversation({
id,
@@ -15,29 +31,28 @@ function ConversationDetail({ navigation, route }) {
});
}
- const { data, error } = useSWR(["getConversation", route.params.id], fetcher);
-
function handleBackActionPress() {
navigation.goBack();
}
- function BackIcon(props) {
- return ;
- }
+ const BackButtonWrapper = () => ;
+ const SubjectWrapper = () => (
+
+ );
- function renderBackButton() {
- return ;
- }
+ const { data, error } = useSWR(["getConversation", route.params.id], fetcher);
return (
-
-
+
+
-
- { data ? (
-
+ {data ? (
+
) : (
- Loading...
+ <>
+
+
+ >
)}
);
diff --git a/components/conversation/DetailSubject.js b/components/conversation/DetailSubject.js
new file mode 100644
index 0000000..0e34020
--- /dev/null
+++ b/components/conversation/DetailSubject.js
@@ -0,0 +1,24 @@
+import { Icon, Text, TopNavigation, TopNavigationAction, useStyleSheet } from "@ui-kitten/components";
+
+import React from "react";
+import themedStyles from "../../styles";
+
+const StarIcon = (props) => ;
+
+function ConversationDetailSubject({ subject }) {
+ const styles = useStyleSheet(themedStyles);
+
+ const SubjectHeading = () => (
+ {subject}
+ );
+
+ const StarAction = () => (
+
+ );
+
+ return (
+
+ );
+}
+
+export default ConversationDetailSubject;
\ No newline at end of file
diff --git a/components/conversation/List.js b/components/conversation/List.js
index f750ff6..a1c918e 100644
--- a/components/conversation/List.js
+++ b/components/conversation/List.js
@@ -1,14 +1,20 @@
-import { Divider, List, Text, TopNavigation } from "@ui-kitten/components";
+import { Divider, Icon, List, TopNavigation, TopNavigationAction, useStyleSheet } from "@ui-kitten/components";
+import { Platform, SafeAreaView } from "react-native";
import ConversationListItem from "./ListItem";
+import LoadingScreen from "../shared/LoadingScreen";
import React from "react";
-import { SafeAreaView } from "react-native";
import { createZimbraClient } from "../../utils";
+import themedStyles from "../../styles";
import useSWR from "swr";
const REFRESH_INTERVAL_SECONDS = 60 * 1000;
+const MenuIcon = (props) => ;
+
function ConversationList({ navigation }) {
+ const styles = useStyleSheet(themedStyles);
+
async function fetcher(_key, query) {
return (await createZimbraClient()).search({ query });
}
@@ -19,25 +25,23 @@ function ConversationList({ navigation }) {
return ;
}
- if (error) {
- console.error(error);
-
- return Error;
- }
+ const MenuAction = () => (
+
+ );
return (
-
-
+
+
{data ? (
) : (
- Loading...
+
)}
);
diff --git a/components/conversation/ListItem.js b/components/conversation/ListItem.js
index a110c1d..aa7e963 100644
--- a/components/conversation/ListItem.js
+++ b/components/conversation/ListItem.js
@@ -7,15 +7,13 @@ function ConversationListItem({ navigation, id, subject, emailAddresses }) {
navigation.navigate("conversationDetail", { id: id, subject: subject });
}
- function renderIcon(props) {
- return ;
- }
+ const PersonIcon = (props) => ;
return (
);
diff --git a/components/message/HtmlViewer.js b/components/message/HtmlViewer.js
index c284eb8..3b503bf 100644
--- a/components/message/HtmlViewer.js
+++ b/components/message/HtmlViewer.js
@@ -1,7 +1,8 @@
-import { Dimensions, Text } from "react-native";
import React, { useState } from "react";
+import { Dimensions } from "react-native";
import { WebView } from "react-native-webview";
+import { useTheme } from "@ui-kitten/components";
const injectedJavascript = `
setTimeout(function() {
@@ -12,19 +13,28 @@ const injectedJavascript = `
}, 10);
true;`;
-const injectedCss = `
+function HtmlViewer({ html }) {
+ const theme = useTheme();
+
+ // Higher starting height seems to lead to better height/width calculations
+ const [height, setHeight] = useState(1000);
+
+ const injectedCss = `
`;
-function HtmlViewer({ html }) {
- // Higher starting height seems to lead to better height/width calculations
- const [height, setHeight] = useState(1000);
-
function handleWebViewMessage(event) {
const { height, width } = JSON.parse(event.nativeEvent.data);
@@ -62,7 +72,7 @@ function HtmlViewer({ html }) {
onMessage={handleWebViewMessage}
injectedJavaScript={injectedJavascript}
scrollEnabled={false}
- style={{ flex: 0, height: height }}
+ style={{ backgroundColor: theme["background-basic-color-1"], flex: 0, height: height }}
/>
);
}
diff --git a/components/message/List.js b/components/message/List.js
index b6afd48..afa1c9d 100644
--- a/components/message/List.js
+++ b/components/message/List.js
@@ -1,13 +1,24 @@
-import { List } from "@ui-kitten/components";
+import { List, useStyleSheet } from "@ui-kitten/components";
+
import MessageListItem from "./ListItem";
import React from "react";
+import themedStyles from "../../styles";
+
+function MessageList({ navigation, messages, ListHeaderComponent }) {
+ const styles = useStyleSheet(themedStyles);
-function MessageList({ navigation, messages }) {
function renderItem({ item }) {
return ;
}
-
- return
;
+
+ return (
+
+ );
}
-export default MessageList;
\ No newline at end of file
+export default MessageList;
diff --git a/components/message/ListItem.js b/components/message/ListItem.js
index 4865a1f..dbc4d3c 100644
--- a/components/message/ListItem.js
+++ b/components/message/ListItem.js
@@ -1,10 +1,12 @@
-import { Icon, Layout, ListItem, Text } from "@ui-kitten/components";
+import { Icon, Layout, ListItem, useStyleSheet } from "@ui-kitten/components";
import HtmlViewer from "./HtmlViewer";
import React from "react";
-import styles from "../../styles";
+import themedStyles from "../../styles";
function MessageListItem({ from, html, to }) {
+ const styles = useStyleSheet(themedStyles);
+
function getToNames() {
return to.map((e) => e.displayName).join(", ");
}
@@ -17,10 +19,10 @@ function MessageListItem({ from, html, to }) {
<>
-
+
>
diff --git a/components/shared/LoadingScreen.js b/components/shared/LoadingScreen.js
new file mode 100644
index 0000000..719ca2c
--- /dev/null
+++ b/components/shared/LoadingScreen.js
@@ -0,0 +1,16 @@
+import { Layout, Spinner, Text, useStyleSheet } from "@ui-kitten/components";
+
+import React from "react";
+import themedStyles from "../../styles";
+
+function LoadingScreen({ level, error }) {
+ const styles = useStyleSheet(themedStyles);
+
+ return (
+
+ {error ? Sorry, failed to load. : }
+
+ );
+}
+
+export default LoadingScreen;
diff --git a/package.json b/package.json
index 5e98d31..e76bad5 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"react": "~16.9.0",
"react-dom": "~16.9.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
+ "react-native-appearance": "~0.3.3",
"react-native-gesture-handler": "~1.6.0",
"react-native-reanimated": "~1.7.0",
"react-native-safe-area-context": "0.7.3",
diff --git a/styles.js b/styles.js
index efde615..098f6ab 100644
--- a/styles.js
+++ b/styles.js
@@ -1,24 +1,39 @@
-import { StyleSheet } from "react-native";
+import { Platform, StatusBar } from "react-native";
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: "#fff",
- alignItems: "center",
- justifyContent: "center"
- },
+import { StyleService } from "@ui-kitten/components";
+const styles = StyleService.create({
paddedLayout: {
flex: 1,
- paddingVertical: 20,
- paddingHorizontal: 20
+ paddingVertical: 10, // This should match the design system
+ paddingHorizontal: 20 // This should match the design system
},
centeredLayout: {
alignItems: "center",
flex: 1,
justifyContent: "center"
+ },
+
+ safeAreaView: {
+ backgroundColor: "background-basic-color-1",
+ flex: 1,
+ ...Platform.select({
+ android: {
+ paddingTop: StatusBar.currentHeight
+ }
+ })
+ },
+
+ topNavigation: {},
+
+ list: {
+ backgroundColor: "background-basic-color-1"
+ },
+
+ subjectHeading: {
+ paddingLeft: 11
}
});
-export default styles;
+export default styles;
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 3cfcf01..1992d8c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4649,6 +4649,15 @@ react-is@^16.12.0, react-is@^16.13.0, react-is@^16.7.0, react-is@^16.8.1, react-
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-native-appearance@~0.3.3:
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/react-native-appearance/-/react-native-appearance-0.3.4.tgz#2cbcbc5142cdc1898c116684f519b16c879cbec2"
+ integrity sha512-Vz3zdJbAEiMDwuw6wH98TT1WVfBvWjvANutYtkIbl16KGRCigtSgt6IIiLsF3/TSS3y3FtHhWDelFeGw/rtuig==
+ dependencies:
+ fbemitter "^2.1.1"
+ invariant "^2.2.4"
+ use-subscription "^1.0.0"
+
react-native-eva-icons@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/react-native-eva-icons/-/react-native-eva-icons-1.3.1.tgz#1e6e019b0fd3cb1669db50bd6bbdaa6d89327593"
@@ -5661,7 +5670,7 @@ url-parse@^1.4.4:
querystringify "^2.1.1"
requires-port "^1.0.0"
-use-subscription@^1.4.0:
+use-subscription@^1.0.0, use-subscription@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.4.1.tgz#edcbcc220f1adb2dd4fa0b2f61b6cc308e620069"
integrity sha512-7+IIwDG/4JICrWHL/Q/ZPK5yozEnvRm6vHImu0LKwQlmWGKeiF7mbAenLlK/cTNXrTtXHU/SFASQHzB6+oSJMQ==