From f282a1dd849470461bb893dfa541eaf6c5cfb5b1 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet <vergnet@etud.insa-toulouse.fr> Date: Thu, 9 Apr 2020 23:59:45 +0200 Subject: [PATCH] Further theme switching improvements --- src/components/Custom/CustomAgenda.js | 3 +- src/components/Custom/CustomHTML.js | 44 +++++++++++++++++++ .../Home/PreviewEventDashboardItem.js | 14 ++---- .../Amicale/Clubs/ClubDisplayScreen.js | 14 +----- src/screens/Amicale/ProfileScreen.js | 39 ++++++---------- src/screens/Planning/PlanningDisplayScreen.js | 17 ++----- 6 files changed, 68 insertions(+), 63 deletions(-) create mode 100644 src/components/Custom/CustomHTML.js diff --git a/src/components/Custom/CustomAgenda.js b/src/components/Custom/CustomAgenda.js index 3d9d15f..b490fc7 100644 --- a/src/components/Custom/CustomAgenda.js +++ b/src/components/Custom/CustomAgenda.js @@ -45,7 +45,8 @@ class CustomAgenda extends React.Component<Props> { } render() { - if (this.props.theme.colors.text === "#ffffff") // We are in light mode + // Completely recreate the component on theme change to force theme reload + if (this.props.theme.dark) return ( <View style={{flex: 1}}> {this.getAgenda()} diff --git a/src/components/Custom/CustomHTML.js b/src/components/Custom/CustomHTML.js new file mode 100644 index 0000000..f04adca --- /dev/null +++ b/src/components/Custom/CustomHTML.js @@ -0,0 +1,44 @@ +import * as React from 'react'; +import {View} from "react-native"; +import {withTheme} from 'react-native-paper'; +import HTML from "react-native-render-html"; +import {Linking} from "expo"; + +type Props = { + theme: Object, + html: string, +} + +/** + * Abstraction layer for Agenda component, using custom configuration + */ +class CustomHTML extends React.Component<Props> { + + openWebLink = (event, link) => { + Linking.openURL(link).catch((err) => console.error('Error opening link', err)); + }; + + getHTML() { + // Surround description with div to allow text styling if the description is not html + return <HTML html={"<div>" + this.props.html + "</div>"} + tagsStyles={{ + p: {color: this.props.theme.colors.text}, + div: {color: this.props.theme.colors.text} + }} + onLinkPress={this.openWebLink}/>; + } + + render() { + // Completely recreate the component on theme change to force theme reload + if (this.props.theme.dark) + return ( + <View style={{flex: 1}}> + {this.getHTML()} + </View> + ); + else + return this.getHTML(); + } +} + +export default withTheme(CustomHTML); diff --git a/src/components/Home/PreviewEventDashboardItem.js b/src/components/Home/PreviewEventDashboardItem.js index d77b3f1..90aa197 100644 --- a/src/components/Home/PreviewEventDashboardItem.js +++ b/src/components/Home/PreviewEventDashboardItem.js @@ -2,10 +2,10 @@ import * as React from 'react'; import {StyleSheet, View} from "react-native"; -import HTML from "react-native-render-html"; import i18n from "i18n-js"; -import {Avatar, Button, Card, withTheme} from 'react-native-paper'; +import {Avatar, Button, Card} from 'react-native-paper'; import {getFormattedEventTime, isDescriptionEmpty} from "../../utils/Planning"; +import CustomHTML from "../Custom/CustomHTML"; /** * Component used to display an event preview if an event is available @@ -14,7 +14,6 @@ import {getFormattedEventTime, isDescriptionEmpty} from "../../utils/Planning"; * @return {*} */ function PreviewEventDashboardItem(props) { - const {colors} = props.theme; const isEmpty = props.event === undefined ? true : isDescriptionEmpty(props.event['description']); @@ -43,12 +42,7 @@ function PreviewEventDashboardItem(props) { />} {!isEmpty ? <Card.Content style={styles.content}> - <HTML html={"<div>" + props.event['description'] + "</div>"} - tagsStyles={{ - p: {color: colors.text,}, - div: {color: colors.text}, - }}/> - + <CustomHTML html={props.event['description']}/> </Card.Content> : null} <Card.Actions style={styles.actions}> @@ -82,4 +76,4 @@ const styles = StyleSheet.create({ } }); -export default withTheme(PreviewEventDashboardItem); +export default PreviewEventDashboardItem; diff --git a/src/screens/Amicale/Clubs/ClubDisplayScreen.js b/src/screens/Amicale/Clubs/ClubDisplayScreen.js index 2feafd0..54a2c08 100644 --- a/src/screens/Amicale/Clubs/ClubDisplayScreen.js +++ b/src/screens/Amicale/Clubs/ClubDisplayScreen.js @@ -2,12 +2,11 @@ import * as React from 'react'; import {ScrollView, View} from 'react-native'; -import HTML from "react-native-render-html"; -import {Linking} from "expo"; import {Avatar, Card, Chip, Paragraph, withTheme} from 'react-native-paper'; import ImageModal from 'react-native-image-modal'; import i18n from "i18n-js"; import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen"; +import CustomHTML from "../../../components/Custom/CustomHTML"; type Props = { navigation: Object, @@ -18,10 +17,6 @@ type State = { imageModalVisible: boolean, }; -function openWebLink(event, link) { - Linking.openURL(link).catch((err) => console.error('Error opening link', err)); -} - /** * Class defining a club event information page. * If called with data and categories navigation parameters, will use those to display the data. @@ -146,12 +141,7 @@ class ClubDisplayScreen extends React.Component<Props, State> { {data.description !== null ? // Surround description with div to allow text styling if the description is not html <Card.Content> - <HTML html={"<div>" + data.description + "</div>"} - tagsStyles={{ - p: {color: this.colors.text,}, - div: {color: this.colors.text} - }} - onLinkPress={openWebLink}/> + <CustomHTML html={data.description}/> </Card.Content> : <View/>} {this.getManagersRender(data.responsibles)} diff --git a/src/screens/Amicale/ProfileScreen.js b/src/screens/Amicale/ProfileScreen.js index 10f6dbd..4f029dc 100644 --- a/src/screens/Amicale/ProfileScreen.js +++ b/src/screens/Amicale/ProfileScreen.js @@ -24,15 +24,12 @@ class ProfileScreen extends React.Component<Props, State> { dialogVisible: false, }; - colors: Object; - data: Object; flatListData: Array<Object>; - constructor(props) { - super(props); - this.colors = props.theme.colors; + constructor() { + super(); this.flatListData = [ {id: '0'}, {id: '1'}, @@ -104,18 +101,6 @@ class ProfileScreen extends React.Component<Props, State> { : i18n.t("profileScreen.noData"); } - /** - * Gets the color depending on the value. - * - * @param field The field to get the color for - * @return {*} - */ - getFieldColor(field: ?string) { - return this.isFieldAvailable(field) - ? this.colors.text - : this.colors.textDisabled; - } - /** * Gets a list item showing personal information * @@ -124,15 +109,17 @@ class ProfileScreen extends React.Component<Props, State> { * @return {*} */ getPersonalListItem(field: ?string, icon: string) { + let title = this.isFieldAvailable(field) ? this.getFieldValue(field) : ':('; + let subtitle = this.isFieldAvailable(field) ? '' : this.getFieldValue(field); return ( <List.Item - title={this.getFieldValue(field)} + title={title} + description={subtitle} left={props => <List.Icon {...props} icon={icon} - color={this.getFieldColor(field)} + color={this.isFieldAvailable(field) ? undefined : this.props.theme.colors.textDisabled} />} - titleStyle={{color: this.getFieldColor(field)}} /> ); } @@ -151,7 +138,7 @@ class ProfileScreen extends React.Component<Props, State> { left={(props) => <Avatar.Icon {...props} icon="account" - color={this.colors.primary} + color={this.props.theme.colors.primary} style={styles.icon} />} /> @@ -169,7 +156,7 @@ class ProfileScreen extends React.Component<Props, State> { <Button icon="account-edit" mode="contained" - onPress={() => openBrowser(this.data.link, this.colors.primary)} + onPress={() => openBrowser(this.data.link, this.props.theme.colors.primary)} style={styles.editButton}> {i18n.t("profileScreen.editInformation")} </Button> @@ -193,7 +180,7 @@ class ProfileScreen extends React.Component<Props, State> { left={(props) => <Avatar.Icon {...props} icon="account-group" - color={this.colors.primary} + color={this.props.theme.colors.primary} style={styles.icon} />} /> @@ -219,7 +206,7 @@ class ProfileScreen extends React.Component<Props, State> { left={(props) => <Avatar.Icon {...props} icon="credit-card" - color={this.colors.primary} + color={this.props.theme.colors.primary} style={styles.icon} />} /> @@ -243,7 +230,7 @@ class ProfileScreen extends React.Component<Props, State> { title={state ? i18n.t("profileScreen.membershipPayed") : i18n.t("profileScreen.membershipNotPayed")} left={props => <List.Icon {...props} - color={state ? this.colors.success : this.colors.danger} + color={state ? this.props.theme.colors.success : this.props.theme.colors.danger} icon={state ? 'check' : 'close'} />} /> @@ -270,7 +257,7 @@ class ProfileScreen extends React.Component<Props, State> { let icon = (props) => <List.Icon {...props} icon="chevron-right"/>; if (item.is_manager) { description = i18n.t("profileScreen.isManager"); - icon = (props) => <List.Icon {...props} icon="star" color={this.colors.primary}/>; + icon = (props) => <List.Icon {...props} icon="star" color={this.props.theme.colors.primary}/>; } return <List.Item title={item.name} diff --git a/src/screens/Planning/PlanningDisplayScreen.js b/src/screens/Planning/PlanningDisplayScreen.js index c3efca0..07254a1 100644 --- a/src/screens/Planning/PlanningDisplayScreen.js +++ b/src/screens/Planning/PlanningDisplayScreen.js @@ -2,8 +2,6 @@ import * as React from 'react'; import {ScrollView, View} from 'react-native'; -import HTML from "react-native-render-html"; -import {Linking} from "expo"; import {getDateOnlyString, getFormattedEventTime} from '../../utils/Planning'; import {Card, withTheme} from 'react-native-paper'; import DateManager from "../../managers/DateManager"; @@ -11,6 +9,7 @@ import ImageModal from 'react-native-image-modal'; import BasicLoadingScreen from "../../components/Custom/BasicLoadingScreen"; import {apiRequest} from "../../utils/WebData"; import ErrorView from "../../components/Custom/ErrorView"; +import CustomHTML from "../../components/Custom/CustomHTML"; type Props = { navigation: Object, @@ -21,10 +20,6 @@ type State = { loading: boolean }; -function openWebLink(event, link) { - Linking.openURL(link).catch((err) => console.error('Error opening link', err)); -} - const CLUB_INFO_PATH = "event/info"; /** @@ -111,14 +106,8 @@ class PlanningDisplayScreen extends React.Component<Props, State> { : <View/>} {this.displayData.description !== null ? - // Surround description with div to allow text styling if the description is not html <Card.Content> - <HTML html={"<div>" + this.displayData.description + "</div>"} - tagsStyles={{ - p: {color: this.colors.text,}, - div: {color: this.colors.text} - }} - onLinkPress={openWebLink}/> + <CustomHTML html={this.displayData.description}/> </Card.Content> : <View/>} </ScrollView> @@ -131,7 +120,7 @@ class PlanningDisplayScreen extends React.Component<Props, State> { else if (this.errorCode === 0) return this.getContent(); else - return <ErrorView {...this.props} errorCode={this.errorCode} onRefresh={this.fetchData}/>; + return <ErrorView {...this.props} errorCode={this.errorCode} onRefresh={this.fetchData}/>; } }