feat(polls/native): New polls screen (#11741)

* feat(polls/native) style updates
This commit is contained in:
Calinteodor 2022-06-27 16:53:52 +03:00 committed by GitHub
parent ec47f530bc
commit de37c3e809
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 197 additions and 152 deletions

View File

@ -243,8 +243,8 @@ export const colorMap = {
// Line separators
border03: 'surface04',
border04: 'primary12',
border05: 'surface07',
// Color for error border & message
borderError: 'error06',

View File

@ -9,7 +9,6 @@ import {
getClientHeight,
getClientWidth
} from '../../../base/modal/components/functions.native';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import { screen } from '../../../mobile/navigation/routes';
import { chatTabBarOptions } from '../../../mobile/navigation/screenOptions';
import { PollsPane } from '../../../polls/components';
@ -27,12 +26,7 @@ const ChatAndPolls = () => {
height: clientHeight,
width: clientWidth
}}
screenOptions = {{
...chatTabBarOptions,
tabBarStyle: {
backgroundColor: BaseTheme.palette.ui01
}
}}>
screenOptions = { chatTabBarOptions }>
<ChatTab.Screen
component = { Chat }
name = { screen.conference.chatandpolls.tab.chat } />

View File

@ -41,7 +41,8 @@ export default {
alignSelf: 'center',
flex: 1,
padding: BoxModel.padding,
paddingTop: '8%'
paddingTop: '8%',
maxWidth: '80%'
},
/**

View File

@ -152,13 +152,19 @@ export const conferenceScreenOptions = {
* Tab bar options for chat screen.
*/
export const chatTabBarOptions = {
tabBarActiveTintColor: BaseTheme.palette.screen01Header,
tabBarActiveTintColor: BaseTheme.palette.field02,
tabBarLabelStyle: {
fontSize: BaseTheme.typography.labelRegular.fontSize
fontSize: BaseTheme.typography.labelRegular.fontSize,
textTransform: 'capitalize'
},
tabBarInactiveTintColor: BaseTheme.palette.text01,
tabBarInactiveTintColor: BaseTheme.palette.text03,
tabBarIndicatorStyle: {
backgroundColor: BaseTheme.palette.screen01Header
backgroundColor: BaseTheme.palette.field02
},
tabBarStyle: {
backgroundColor: BaseTheme.palette.ui01,
borderBottomColor: BaseTheme.palette.border05,
borderBottomWidth: 1
}
};

View File

@ -3,7 +3,9 @@
import React from 'react';
import { Switch, Text, View } from 'react-native';
import { Button } from 'react-native-paper';
import { useSelector } from 'react-redux';
import { getLocalParticipant } from '../../../base/participants';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import { BUTTON_MODES } from '../../../chat/constants';
import { isSubmitAnswerDisabled } from '../../functions';
@ -24,12 +26,15 @@ const PollAnswer = (props: AbstractProps) => {
t
} = props;
const { changingVote } = poll;
const localParticipant = useSelector(getLocalParticipant);
return (
<View>
<View>
<Text style = { dialogStyles.question } >{ poll.question }</Text>
</View>
<>
<Text style = { dialogStyles.questionText } >{ poll.question }</Text>
<Text style = { dialogStyles.questionOwnerText } >{
t('polls.by', { name: localParticipant.name })
}
</Text>
<View style = { chatStyles.answerContent }>
{poll.answers.map((answer, index) => (
<View
@ -38,6 +43,7 @@ const PollAnswer = (props: AbstractProps) => {
<Switch
/* eslint-disable react/jsx-no-bind */
onValueChange = { state => setCheckbox(index, state) }
trackColor = {{ true: BaseTheme.palette.action01 }}
value = { checkBoxStates[index] } />
<Text style = { chatStyles.switchLabel }>{answer.name}</Text>
</View>
@ -46,13 +52,14 @@ const PollAnswer = (props: AbstractProps) => {
<View style = { chatStyles.buttonRow }>
<Button
color = { BaseTheme.palette.action02 }
labelStyle = { chatStyles.pollButtonLabel }
mode = { BUTTON_MODES.CONTAINED }
onPress = { changingVote ? skipChangeVote : skipAnswer }
style = { chatStyles.pollCreateButton } >
{t('polls.answer.skip')}
{ t('polls.answer.skip') }
</Button>
<Button
color = { BaseTheme.palette.screen01Header }
color = { BaseTheme.palette.action01 }
disabled = { isSubmitAnswerDisabled(checkBoxStates) }
labelStyle = {
isSubmitAnswerDisabled(checkBoxStates)
@ -62,10 +69,10 @@ const PollAnswer = (props: AbstractProps) => {
mode = { BUTTON_MODES.CONTAINED }
onPress = { submitAnswer }
style = { chatStyles.pollCreateButton } >
{t('polls.answer.submit')}
{ t('polls.answer.submit') }
</Button>
</View>
</View>
</>
);
};

View File

@ -1,12 +1,13 @@
// @flow
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { View, TextInput, FlatList, TouchableOpacity } from 'react-native';
import { Button } from 'react-native-paper';
import { View, Text, TextInput, FlatList } from 'react-native';
import { Button, Divider, TouchableRipple } from 'react-native-paper';
import { Icon, IconClose } from '../../../base/icons';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import { BUTTON_MODES } from '../../../chat/constants';
import styles
from '../../../welcome/components/native/settings/components/styles';
import { ANSWERS_LIMIT, CHAR_LIMIT } from '../../constants';
import AbstractPollCreate from '../AbstractPollCreate';
import type { AbstractProps } from '../AbstractPollCreate';
@ -34,7 +35,7 @@ const PollCreate = (props: AbstractProps) => {
/*
* This ref stores the Array of answer input fields, allowing us to focus on them.
* This array is maintained by registerfieldRef and the useEffect below.
* This array is maintained by registerFieldRef and the useEffect below.
*/
const answerInputs = useRef([]);
const registerFieldRef = useCallback((i, input) => {
@ -86,16 +87,14 @@ const PollCreate = (props: AbstractProps) => {
}, [ answers, addAnswer, removeAnswer, requestFocus ]);
/* eslint-disable react/no-multi-comp */
const createIconButton = (icon, onPress, style) => (
<TouchableOpacity
activeOpacity = { 0.8 }
const createRemoveOptionButton = onPress => (
<TouchableRipple
onPress = { onPress }
style = { [ dialogStyles.buttonContainer, style ] }>
<Icon
size = { 24 }
src = { icon }
style = { dialogStyles.icon } />
</TouchableOpacity>
rippleColor = { 'transparent' } >
<Text style = { dialogStyles.optionRemoveButtonText }>
{ t('polls.create.removeOption') }
</Text>
</TouchableRipple>
);
@ -106,6 +105,9 @@ const PollCreate = (props: AbstractProps) => {
(
<View
style = { dialogStyles.optionContainer }>
<Text style = { dialogStyles.optionFieldLabel }>
{ t('polls.create.pollOption', { index: index + 1 }) }
</Text>
<TextInput
blurOnSubmit = { false }
maxLength = { CHAR_LIMIT }
@ -115,13 +117,13 @@ const PollCreate = (props: AbstractProps) => {
placeholder = { t('polls.create.answerPlaceholder', { index: index + 1 }) }
placeholderTextColor = { BaseTheme.palette.text03 }
ref = { input => registerFieldRef(index, input) }
selectionColor = { BaseTheme.palette.text03 }
selectionColor = { BaseTheme.palette.action01 }
style = { dialogStyles.field }
value = { answers[index] } />
{
answers.length > 2
&& createIconButton(IconClose, () => removeAnswer(index))
&& createRemoveOptionButton(() => removeAnswer(index))
}
</View>
);
@ -129,6 +131,9 @@ const PollCreate = (props: AbstractProps) => {
return (
<View style = { chatStyles.pollCreateContainer }>
<View style = { chatStyles.pollCreateSubContainer }>
<Text style = { chatStyles.questionFieldLabel }>
{ t('polls.create.pollQuestion') }
</Text>
<TextInput
autoFocus = { true }
blurOnSubmit = { false }
@ -138,9 +143,10 @@ const PollCreate = (props: AbstractProps) => {
onSubmitEditing = { onQuestionKeyDown }
placeholder = { t('polls.create.questionPlaceholder') }
placeholderTextColor = { BaseTheme.palette.text03 }
selectionColor = { BaseTheme.palette.text03 }
style = { dialogStyles.question }
selectionColor = { BaseTheme.palette.action01 }
style = { dialogStyles.questionField }
value = { question } />
<Divider style = { styles.fieldSeparator } />
<FlatList
blurOnSubmit = { true }
data = { answers }
@ -152,6 +158,7 @@ const PollCreate = (props: AbstractProps) => {
<Button
color = { BaseTheme.palette.action02 }
disabled = { answers.length >= ANSWERS_LIMIT }
labelStyle = { chatStyles.pollButtonLabel }
mode = { BUTTON_MODES.CONTAINED }
onPress = { () => {
// adding and answer
@ -159,19 +166,20 @@ const PollCreate = (props: AbstractProps) => {
requestFocus(answers.length);
} }
style = { chatStyles.pollCreateAddButton }>
{t('polls.create.addOption')}
{ t('polls.create.addOption') }
</Button>
<View
style = { chatStyles.buttonRow }>
<Button
color = { BaseTheme.palette.action02 }
labelStyle = { chatStyles.pollButtonLabel }
mode = { BUTTON_MODES.CONTAINED }
onPress = { () => setCreateMode(false) }
style = { chatStyles.pollCreateButton } >
{t('polls.create.cancel')}
{ t('polls.create.cancel') }
</Button>
<Button
color = { BaseTheme.palette.screen01Header }
color = { BaseTheme.palette.action01 }
disabled = { isSubmitDisabled }
labelStyle = {
isSubmitDisabled
@ -181,7 +189,7 @@ const PollCreate = (props: AbstractProps) => {
mode = { BUTTON_MODES.CONTAINED }
onPress = { onSubmit }
style = { chatStyles.pollCreateButton } >
{t('polls.create.send')}
{ t('polls.create.send') }
</Button>
</View>
</View>

View File

@ -2,7 +2,9 @@
import React, { useCallback } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useSelector } from 'react-redux';
import { getLocalParticipant } from '../../../base/participants';
import AbstractPollResults from '../AbstractPollResults';
import type { AbstractProps, AnswerInfo } from '../AbstractPollResults';
@ -20,13 +22,12 @@ const PollResults = (props: AbstractProps) => {
answers,
changeVote,
haveVoted,
showDetails,
question,
showDetails,
t,
toggleIsDetailed
} = props;
/* eslint-disable react/no-multi-comp */
/**
* Render a header summing up answer information.
*
@ -41,11 +42,6 @@ const PollResults = (props: AbstractProps) => {
<View>
<Text style = { resultsStyles.answer }>({nbVotes}) {percentage}%</Text>
</View>
{/* <Text style = { resultsStyles.answer }>{ answer } - { percentage }%</Text>
<Text style = { resultsStyles.answerVoteCount }>
{ t('polls.answer.vote', { count: nbVotes }) }
</Text> */}
</View>
);
@ -62,6 +58,9 @@ const PollResults = (props: AbstractProps) => {
return (
<View style = { resultsStyles.answerContainer }>
{ renderHeader(name, percentage, voterCount) }
<View style = { resultsStyles.barContainer }>
<View style = { [ resultsStyles.bar, { width: `${percentage}%` } ] } />
</View>
{ voters && voterCount > 0
&& <View style = { resultsStyles.voters }>
{voters.map(({ id, name: voterName }) =>
@ -89,13 +88,14 @@ const PollResults = (props: AbstractProps) => {
);
}, [ showDetails ]);
const localParticipant = useSelector(getLocalParticipant);
/* eslint-disable react/jsx-no-bind */
return (
<View>
<View>
<Text style = { dialogStyles.question } >{ question }</Text>
</View>
<Text style = { dialogStyles.questionText } >{ question }</Text>
<Text style = { dialogStyles.questionOwnerText } >{ t('polls.by', { name: localParticipant.name }) }</Text>
<FlatList
data = { answers }
keyExtractor = { (item, index) => index.toString() }
@ -104,17 +104,24 @@ const PollResults = (props: AbstractProps) => {
<TouchableOpacity onPress = { toggleIsDetailed }>
<Text
style = { chatStyles.toggleText }>
{showDetails ? t('polls.results.hideDetailedResults') : t('polls.results.showDetailedResults')}
{
showDetails
? t('polls.results.hideDetailedResults')
: t('polls.results.showDetailedResults')
}
</Text>
</TouchableOpacity>
<TouchableOpacity onPress = { changeVote }>
<Text
style = { chatStyles.toggleText }>
{haveVoted ? t('polls.results.changeVote') : t('polls.results.vote')}
{
haveVoted
? t('polls.results.changeVote')
: t('polls.results.vote')
}
</Text>
</TouchableOpacity>
</View>
</View>
);
};

View File

@ -1,9 +1,13 @@
import React, { useCallback, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { FlatList } from 'react-native';
import { FlatList, View } from 'react-native';
import { Text } from 'react-native-paper';
import { useSelector } from 'react-redux';
import { Icon, IconChatUnread } from '../../../base/icons';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import PollItem from './PollItem';
import { chatStyles } from './styles';
@ -33,11 +37,17 @@ const PollsList = () => {
<>
{
listPolls.length === 0
&& <Text style = { chatStyles.noPollText } >
{
t('polls.results.empty')
}
</Text>
&& <View style = { chatStyles.noPollContent }>
<Icon
color = { BaseTheme.palette.icon03 }
size = { 160 }
src = { IconChatUnread } />
<Text style = { chatStyles.noPollText } >
{
t('polls.results.empty')
}
</Text>
</View>
}
<FlatList
data = { listPolls }

View File

@ -36,9 +36,9 @@ const PollsPane = (props: AbstractProps) => {
return (
<JitsiScreen
contentContainerStyle = { chatStyles.PollPane }
contentContainerStyle = { chatStyles.pollPane }
hasTabNavigator = { true }
style = { chatStyles.PollPaneContainer }>
style = { chatStyles.pollPaneContainer }>
{
createMode
? <PollCreate setCreateMode = { setCreateMode } />
@ -47,7 +47,8 @@ const PollsPane = (props: AbstractProps) => {
}
{
!createMode && <Button
color = { palette.screen01Header }
color = { palette.action01 }
labelStyle = { chatStyles.pollButtonLabel }
mode = { BUTTON_MODES.CONTAINED }
onPress = { onCreate }
style = { chatStyles.createPollButton } >

View File

@ -1,60 +1,63 @@
// @flow
import { ColorPalette, createStyleSheet } from '../../../base/styles';
import { createStyleSheet } from '../../../base/styles';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
export const answerStyles = createStyleSheet({
question: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 6
},
answer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 3
},
option: {
flexShrink: 1
}
});
export const dialogStyles = createStyleSheet({
question: {
questionText: {
...BaseTheme.typography.bodyShortBold,
color: BaseTheme.palette.text01,
fontSize: 16,
fontWeight: 'bold',
marginVertical: 4
marginBottom: BaseTheme.spacing[2],
marginLeft: BaseTheme.spacing[2]
},
questionOwnerText: {
...BaseTheme.typography.bodyShortBold,
color: BaseTheme.palette.text03,
marginBottom: BaseTheme.spacing[2],
marginLeft: BaseTheme.spacing[2]
},
questionField: {
borderWidth: 1,
borderColor: BaseTheme.palette.border05,
borderRadius: BaseTheme.shape.borderRadius,
color: BaseTheme.palette.text01,
fontSize: 14,
marginHorizontal: BaseTheme.spacing[3],
marginBottom: BaseTheme.spacing[3],
paddingBottom: BaseTheme.spacing[2],
paddingLeft: BaseTheme.spacing[3],
paddingRight: BaseTheme.spacing[3],
paddingTop: BaseTheme.spacing[2]
},
optionContainer: {
flexDirection: 'row'
flexDirection: 'column',
marginTop: BaseTheme.spacing[3],
marginHorizontal: BaseTheme.spacing[3]
},
optionFieldLabel: {
color: BaseTheme.palette.text03,
marginBottom: BaseTheme.spacing[2]
},
optionRemoveButtonText: {
color: BaseTheme.palette.actionDangerActive
},
field: {
borderWidth: 1,
borderColor: BaseTheme.palette.border05,
borderRadius: BaseTheme.shape.borderRadius,
color: BaseTheme.palette.text01,
borderBottomWidth: 1,
borderColor: ColorPalette.blue,
fontSize: 14,
flexGrow: 1,
paddingBottom: 0,
flexShrink: 1
},
buttonContainer: {
justifyContent: 'flex-end',
alignItems: 'center'
},
icon: {
color: ColorPalette.white,
backgroundColor: ColorPalette.blue,
borderRadius: 5,
margin: 0
},
plusButton: {
marginTop: 8
paddingBottom: BaseTheme.spacing[2],
paddingLeft: BaseTheme.spacing[3],
paddingRight: BaseTheme.spacing[3],
paddingTop: BaseTheme.spacing[2]
}
});
@ -73,18 +76,18 @@ export const resultsStyles = createStyleSheet({
},
bar: {
backgroundColor: ColorPalette.blue,
borderRadius: 3,
backgroundColor: BaseTheme.palette.action01,
borderRadius: BaseTheme.shape.borderRadius,
height: 6
},
voters: {
borderRadius: 3,
backgroundColor: BaseTheme.palette.ui04,
borderColor: BaseTheme.palette.border03,
borderRadius: BaseTheme.shape.borderRadius,
borderWidth: 1,
borderColor: 'gray',
padding: 2,
marginHorizontal: 8,
marginVertical: 4
padding: BaseTheme.spacing[2],
marginTop: BaseTheme.spacing[2]
},
voter: {
@ -92,7 +95,8 @@ export const resultsStyles = createStyleSheet({
},
answerContainer: {
marginVertical: 2,
marginHorizontal: BaseTheme.spacing[2],
marginVertical: BaseTheme.spacing[3],
maxWidth: '100%'
},
@ -116,58 +120,65 @@ export const resultsStyles = createStyleSheet({
});
export const chatStyles = createStyleSheet({
messageFooter: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
fontSize: 11,
marginTop: 6
questionFieldLabel: {
color: BaseTheme.palette.text03,
marginBottom: BaseTheme.spacing[2],
marginLeft: BaseTheme.spacing[3]
},
showDetails: {
fontWeight: 'bold'
noPollContent: {
alignItems: 'center',
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
paddingTop: '4%'
},
noPollText: {
flex: 1,
color: BaseTheme.palette.text03,
textAlign: 'center',
paddingTop: '8%'
maxWidth: '70%'
},
pollItemContainer: {
borderRadius: 4,
borderColor: '#2183ad',
borderWidth: 2,
padding: 16,
marginBottom: 8
backgroundColor: BaseTheme.palette.ui02,
borderColor: BaseTheme.palette.border05,
borderRadius: BaseTheme.shape.borderRadius,
boxShadow: BaseTheme.shape.boxShadow,
borderWidth: 1,
padding: BaseTheme.spacing[2],
margin: BaseTheme.spacing[3]
},
pollCreateContainer: {
flex: 1,
justifyContent: 'space-between'
},
pollCreateSubContainer: {
flex: 1
},
pollCreateSubContainer: {
flex: 1,
marginTop: BaseTheme.spacing[3]
},
pollCreateButtonsContainer: {
paddingVertical: '8%'
marginHorizontal: BaseTheme.spacing[3],
marginVertical: '8%'
},
pollCreateButton: {
flex: 1,
padding: 4,
marginHorizontal: BaseTheme.spacing[2]
},
pollSendLabel: {
color: BaseTheme.palette.text01
color: BaseTheme.palette.text01,
textTransform: 'capitalize'
},
pollSendDisabledLabel: {
color: BaseTheme.palette.text03
color: BaseTheme.palette.text03,
textTransform: 'capitalize'
},
buttonRow: {
@ -181,7 +192,7 @@ export const chatStyles = createStyleSheet({
switchRow: {
alignItems: 'center',
flexDirection: 'row',
padding: 6
padding: BaseTheme.spacing[2]
},
switchLabel: {
@ -189,39 +200,39 @@ export const chatStyles = createStyleSheet({
marginLeft: BaseTheme.spacing[2]
},
pollButtonLabel: {
textTransform: 'capitalize'
},
pollCreateAddButton: {
margin: BaseTheme.spacing[2]
margin: BaseTheme.spacing[2],
padding: BaseTheme.spacing[1]
},
toggleText: {
color: ColorPalette.blue,
color: BaseTheme.palette.action01,
paddingTop: BaseTheme.spacing[3]
},
createPollButton: {
padding: 8,
marginHorizontal: BaseTheme.spacing[2],
marginVertical: BaseTheme.spacing[4]
padding: 4,
marginHorizontal: BaseTheme.spacing[4],
marginVertical: '8%'
},
PollPane: {
pollPane: {
flex: 1,
padding: 8
},
PollPaneContainer: {
pollPaneContainer: {
backgroundColor: BaseTheme.palette.ui01,
flex: 1
},
PollPaneContent: {
justifyContent: 'space-between',
padding: BaseTheme.spacing[3],
flex: 1
},
bottomLinks: {
flexDirection: 'row',
justifyContent: 'space-between'
justifyContent: 'space-between',
marginHorizontal: BaseTheme.spacing[2]
}
});