Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ej/settings menu #732

Merged
merged 20 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions messages/renderer/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"description": "MapFilter tab label",
"message": "Observations"
},
"renderer.components.Home.settings": {
"description": "Settings tab label",
"message": "Settings"
},
"renderer.components.Home.sync": {
"description": "Synchronize tab label",
"message": "Synchronize"
Expand Down Expand Up @@ -464,6 +468,18 @@
"description": "Name to show for an observation when it does not match any preset",
"message": "Observation"
},
"renderer.components.SettingsView.AboutMapeo.mapeoVariant": {
"message": "Mapeo Variant"
},
"renderer.components.SettingsView.AboutMapeo.mapeoVersion": {
"message": "Mapeo Version"
},
"renderer.components.SettingsView.index.aboutMapeo": {
"message": "About Mapeo"
},
"renderer.components.SettingsView.index.aboutMapeoSubtitle": {
"message": "Version and build number"
},
"renderer.components.SyncView.Searching.searchingHint": {
"description": "Hint on sync screen when searching on wifi for devices",
"message": "Make sure devices are turned on and connected to the same wifi network"
Expand Down
27 changes: 18 additions & 9 deletions src/renderer/components/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import LocationOn from '@material-ui/icons/LocationOn'
import MapIcon from '@material-ui/icons/Map'
import ObservationIcon from '@material-ui/icons/PhotoLibrary'
import SyncIcon from '@material-ui/icons/OfflineBolt'
import SettingsIcon from '@material-ui/icons/Settings'
import WarningIcon from '@material-ui/icons/Warning'

import LatLonDialog from './dialogs/LatLon'
Expand All @@ -18,6 +19,8 @@ import { defineMessages, useIntl } from 'react-intl'
import createPersistedState from '../hooks/createPersistedState'
import SyncView from './SyncView'
import { STATES as updateStates, UpdaterView, UpdateTab } from './UpdaterView'
import { SettingsView } from './SettingsView'

import useUpdater from './UpdaterView/useUpdater'
import Loading from './Loading'
import buildConfig from '../../build-config'
Expand Down Expand Up @@ -45,6 +48,8 @@ const m = defineMessages({
mapfilter: 'Observations',
// Synchronize tab label
sync: 'Synchronize',
// Settings tab label
settings: 'Settings',
update: 'Update Mapeo'
})

Expand Down Expand Up @@ -108,11 +113,17 @@ const MapeoIcon = styled(LocationOn)`
`

const StyledTabs = styled(Tabs)`
height: 100%;

border-right: 1px solid rgba(0, 0, 0, 0.12);
-webkit-app-region: no-drag;
.PrivateTabIndicator-root-1 {
background-color: #ff9933;
}

.MuiTabs-flexContainerVertical {
height: 100%;
}
`

const StyledTab = styled(Tab)`
Expand Down Expand Up @@ -154,13 +165,6 @@ const StyledPanel = styled.div`
}
`

const Version = styled.div`
align-self: flex-start;
margin: auto 10px 10px 10px;
font-size: 0.8rem;
color: ${buildConfig.variant === 'icca' ? '#eeeeee' : '#aaaaaa'};
`

const LoadingContainer = styled.div`
display: flex;
width: 100%;
Expand Down Expand Up @@ -274,14 +278,18 @@ export default function Home ({ onSelectLanguage }) {
<StyledTab icon={<MapIcon />} label={t(m.mapeditor)} />
<StyledTab icon={<ObservationIcon />} label={t(m.mapfilter)} />
<StyledTab icon={<SyncIcon />} label={t(m.sync)} />
<StyledTab
style={{ marginTop: 'auto' }}
icon={<SettingsIcon />}
label={t(m.settings)}
/>
{hasUpdate && (
<StyledTab
icon={<WarningIcon />}
label={<UpdateTab update={update} />}
/>
)}
</StyledTabs>
<Version>Mapeo v{buildConfig.version}</Version>
</Sidebar>
<TabContent>
<TabPanel value={tabIndex} index={0} component={MapEditor} />
Expand All @@ -292,9 +300,10 @@ export default function Home ({ onSelectLanguage }) {
component={SyncView}
unmountOnExit
/>
<TabPanel value={tabIndex} index={3} component={SettingsView} />
<TabPanel
value={tabIndex}
index={3}
index={4}
component={UpdaterView}
update={update}
setUpdate={setUpdate}
Expand Down
70 changes: 70 additions & 0 deletions src/renderer/components/SettingsView/AboutMapeo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react'
import styled from 'styled-components'
import { Box, Typography, useTheme } from '@material-ui/core'
import { defineMessages, useIntl } from 'react-intl'
import buildConfig from '../../../build-config'

const m = defineMessages({
mapeoVersion: 'Mapeo Version',
mapeoVariant: 'Mapeo Variant'
})

export const AboutMapeoMenu = () => {
const { formatMessage: t } = useIntl()
return (
<Container>
<KeyValuePair
label={t(m.mapeoVersion)}
value={buildConfig.version}
></KeyValuePair>
<KeyValuePair
label={t(m.mapeoVariant)}
value={buildConfig.variant}
></KeyValuePair>
</Container>
)
}

/**
* @typedef label
* @property {string} label
*
* @typedef value
* @property {string} value
*
* @typedef {label & value} Props
*/
/** @param {Props} props */
const KeyValuePair = ({ label, value }) => {
const theme = useTheme()
return (
<Column>
<Typography variant='body1' component='label' style={{ fontWeight: 500 }}>
{label}
</Typography>
<Typography
variant='caption'
component='label'
style={{ color: theme.palette.grey['700'] }}
>
{value}
</Typography>
</Column>
)
}
const Container = styled(Box)`
width: 100%;
background-color: #fff;
padding: 1.2em 1em 1em 2em;
display: flex;
flex-direction: column;
gap: 1em;
&.MuiPaper-rounded {
border-radius: 0;
}
`
const Column = styled.div`
display: flex;
flex-direction: column;
gap: 0.1em;
`
142 changes: 142 additions & 0 deletions src/renderer/components/SettingsView/SettingsMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import * as React from 'react'
import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab'
import { useIntl } from 'react-intl'
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
import styled from 'styled-components'
import { Paper, Typography, useTheme } from '@material-ui/core'

/**
* @typedef {object} tab
* @property {string} tab.tabId
* @property {string | import('react-intl').MessageDescriptor} tab.label
* @property {string | import('react-intl').MessageDescriptor} tab.subtitle
* @property {import('@material-ui/core/OverridableComponent').OverridableComponent<import('@material-ui/core').SvgIconTypeMap<{}, "svg">>} tab.icon
*
* @typedef tabs
* @property {tab[]} tabs
*
* @typedef currentTab
* @property {number} currentTab
*
* @typedef onTabChange
* @property {(e: React.Dispatch<number>) => number} onTabChange
*
* @typedef {tabs & currentTab & onTabChange} Props
*/
/** @param {Props} props */
export const SettingsMenu = ({ tabs, currentTab, onTabChange }) => {
ErikSin marked this conversation as resolved.
Show resolved Hide resolved
lightlii marked this conversation as resolved.
Show resolved Hide resolved
return (
<Paper
style={{
width: 300,
height: '100vh',
borderRadius: 0,
zIndex: 1,
position: 'relative'
}}
>
<StyledTabs
orientation='vertical'
value={currentTab}
onChange={(e, newValue) => onTabChange(newValue)}
>
{tabs.map(tab => (
<Tab
disableRipple
orientation='vertical'
key={tab.tabId}
value={tab.tabId}
component={RenderTab}
tab={tab}
active={tab.tabId === currentTab}
/>
))}
</StyledTabs>
</Paper>
)
}

const RenderTab = React.forwardRef(
(
{ tab: { icon: Icon, label, subtitle }, active, children, ...rest },
ref
) => {
const { formatMessage: t } = useIntl()
const theme = useTheme()

return (
<WrapperRow ref={ref} {...rest}>
<IconContainer>
{Icon ? <Icon style={{ color: theme.palette.grey['600'] }} /> : null}
</IconContainer>
<TitleContainer>
<Typography
variant='body1'
component='label'
style={{
textTransform: 'none',
textAlign: 'left',
cursor: 'pointer'
}}
>
{typeof label === 'string' ? label : t(label)}
</Typography>
<Typography
variant='caption'
component='label'
style={{
textTransform: 'none',
textAlign: 'left',
cursor: 'pointer',
color: theme.palette.grey['700']
}}
>
{typeof subtitle === 'string' ? subtitle : t(subtitle)}
</Typography>
</TitleContainer>
<ChevronRightIcon style={{ opacity: active ? 1 : 0 }} />
</WrapperRow>
)
}
)

const StyledTabs = styled(Tabs)`
height: 100vh;
padding-top: 1em;
& .MuiTabs-indicator {
display: none;
}

& .MuiTab-root {
max-width: 100%;
}
`

const Row = styled.div`
display: flex;
flex-direction: row;
`

const Column = styled.div`
display: flex;
flex-direction: column;
`

const WrapperRow = styled(Row)`
padding: 20px;
align-items: center;
justify-content: space-between;
`

const IconContainer = styled.div`
flex: 1;
padding: 10px 30px 10px 10px;
display: flex;
align-items: center;
`

const TitleContainer = styled(Column)`
justify-content: flex-start;
flex: 8;
`
42 changes: 42 additions & 0 deletions src/renderer/components/SettingsView/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useState } from 'react'
import InfoIcon from '@material-ui/icons/InfoOutlined'
import { SettingsMenu } from './SettingsMenu'
import { defineMessages } from 'react-intl'
import { AboutMapeoMenu } from './AboutMapeo'
import styled from 'styled-components'

const m = defineMessages({
aboutMapeo: 'About Mapeo',
aboutMapeoSubtitle: 'Version and build number'
})

const tabs = /** @typedef {const} */ [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then we want to define this as

/** @type {import('./SettingsMenu')tab[]} */

This means tabId can only equal the tabs that we set, instead of a generic string

{
tabId: 'AboutMapeo',
icon: InfoIcon,
label: m.aboutMapeo,
subtitle: m.aboutMapeoSubtitle
}
]

export const SettingsView = () => {
const initialMenuState = /** {null | number} */ null
lightlii marked this conversation as resolved.
Show resolved Hide resolved
const [menuItem, setMenuItem] = useState(initialMenuState)

return (
<Container>
<SettingsMenu
tabs={tabs}
currentTab={menuItem}
onTabChange={setMenuItem}
/>

{menuItem === 'AboutMapeo' && <AboutMapeoMenu />}
</Container>
)
}

const Container = styled.div`
width: 100%;
display: flex;
`
Loading