Commit d182c2ad authored by Schoumi's avatar Schoumi

Advance on menu and routes, still problem on subdivision in multiple file for the LibraryNav

parent 0f5d84c8
{ {
"semi": false, "semi": false,
"singleQuote": true "singleQuote": true,
"printWidth": 120
} }
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
"editor": "", "editor": "",
"source": "https://github.com/Schoumi/cozy-music.git@build", "source": "https://github.com/Schoumi/cozy-music.git@build",
"developer": { "developer": {
"name": "Schoumi", "name": "Mob-Dev",
"url": "" "url": "https://mob-dev.fr"
}, },
"routes": { "routes": {
"/": { "/": {
...@@ -24,9 +24,10 @@ ...@@ -24,9 +24,10 @@
"type": "io.cozy.apps", "type": "io.cozy.apps",
"verbs": ["GET"] "verbs": ["GET"]
}, },
"mocks todos": { "files": {
"description": "TO REMOVE: only used as demonstration about Cozy App data interactions", "type": "io.cozy.files",
"type": "io.mocks.todos" "description": "Access to Audio Files",
"verbs": ["GET","POST"]
} }
} }
} }
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M11,14C12,14 13.05,14.16 14.2,14.44C13.39,15.31 13,16.33 13,17.5C13,18.39 13.25,19.23 13.78,20H3V18C3,16.81 3.91,15.85 5.74,15.12C7.57,14.38 9.33,14 11,14M11,12C9.92,12 9,11.61 8.18,10.83C7.38,10.05 7,9.11 7,8C7,6.92 7.38,6 8.18,5.18C9,4.38 9.92,4 11,4C12.11,4 13.05,4.38 13.83,5.18C14.61,6 15,6.92 15,8C15,9.11 14.61,10.05 13.83,10.83C13.05,11.61 12.11,12 11,12M18.5,10H20L22,10V12H20V17.5A2.5,2.5 0 0,1 17.5,20A2.5,2.5 0 0,1 15,17.5A2.5,2.5 0 0,1 17.5,15C17.86,15 18.19,15.07 18.5,15.21V10Z" /></svg>
\ No newline at end of file
<svg version="1.1" width="36" height="36" viewBox="0 0 36 36" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>library-solid</title>
<path d="M12.75,3H5.25A1.15,1.15,0,0,0,4,4V33H14V4A1.15,1.15,0,0,0,12.75,3Z" class="clr-i-solid clr-i-solid-path-1"></path><path d="M33.77,31.09l-6.94-18.3a1,1,0,0,0-1.29-.58L22,13.59V9a1,1,0,0,0-1-1H16V33h6V14.69L28.93,33Z" class="clr-i-solid clr-i-solid-path-2"></path>
<rect x="0" y="0" width="36" height="36" fill-opacity="0"/>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 5h-3v5.5c0 1.38-1.12 2.5-2.5 2.5S10 13.88 10 12.5s1.12-2.5 2.5-2.5c.57 0 1.08.19 1.5.51V5h4v2zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" opacity=".1" fill="none"/><path d="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h3c1.66 0 3-1.34 3-3v-7c0-4.97-4.03-9-9-9z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>
\ No newline at end of file
import React from 'react' import React from 'react'
import { hot } from 'react-hot-loader' import { hot } from 'react-hot-loader'
import { Route, Switch, Redirect, HashRouter } from 'react-router-dom' import { Route, Switch, Redirect, HashRouter } from 'react-router-dom'
import { Layout, Main, Content } from 'cozy-ui/react/Layout' import { Layout, Main, Content, Sidebar } from 'cozy-ui/react'
import { Sprite as IconSprite } from 'cozy-ui/react/Icon' import { Sprite as IconSprite } from 'cozy-ui/react/Icon'
import Sidebar from './Sidebar' import Nav from './Nav'
import Recent from './Recent/Recent' import Recent from './Recent/Recent'
import Albums from './List/Albums'
import Artists from './List/Artists'
import Playlists from './List/Playlists' import Playlists from './List/Playlists'
import Genres from './List/Genres' import List from './List/List'
import Library from './List/Library'
const App = () => ( const App = () => (
<HashRouter> <HashRouter>
<Layout> <Layout>
<Sidebar /> <Sidebar>
<Nav />
</Sidebar>
<Main> <Main>
<Content className="app-content"> <Content className="app-content">
<Switch> <Switch>
<Route path="/recent" component={Recent} /> <Route path="/recent" component={Recent} />
<Route path="/playlists" component={Playlists} /> <Route path="/library/albums" component={List} />
<Route path="/artists" component={Artists} /> <Route path="/library/genres" component={List} />
<Route path="/albums" component={Albums} /> <Route path="/library/playlists" component={Library} />
<Route path="/genres" component={Genres} /> <Route path="/parameters" component={Playlists} />
<Redirect from="/" to="/recent" /> <Redirect from="/" to="/recent" />
<Redirect from="/library" to="/library/all" />
<Redirect from="*" to="/recent" /> <Redirect from="*" to="/recent" />
</Switch> </Switch>
</Content> </Content>
......
import React from 'react'
export const Albums = () => (
<p>Albums</p>
)
export default Albums
import React from 'react'
export const Artists = () => (
<p>Artists</p>
)
export default Artists
import React from 'react'
export const Genres = () => (
<p>Genres</p>
)
export default Genres
import React from 'react'
import { Nav as UINav, NavIcon, NavItem, NavText, translate } from 'cozy-ui/react'
import { Layout, Sidebar } from 'cozy-ui/react'
import { NavLink } from 'react-router-dom'
import cx from 'classnames'
import Icon from 'cozy-ui/react/Icon'
import PlaylistIcon from '../../assets/icons/icon-playlist.svg'
import AlbumIcon from '../../assets/icons/icon-album.svg'
import ArtistIcon from '../../assets/icons/icon-artist.svg'
import GenreIcon from '../../assets/icons/icon-track.svg'
import styles from 'cozy-ui/react/Nav/styles.styl'
export const Library = ({ t }) => (
<Layout>
<Sidebar>
<UINav>
<NavItem>
<NavLink to="/library/playlists" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<NavIcon icon={PlaylistIcon} />
<NavText>{t('Nav.playlists')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/albums" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={AlbumIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.albums')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/artists" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={ArtistIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.artists')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/genres" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={GenreIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.genres')}</NavText>
</NavLink>
</NavItem>
</UINav>
</Sidebar>
</Layout>
)
// translate() provide t() to use translations (ex: locales/en.json)
export default translate()(Library)
import React from 'react'
import { Nav as UINav, NavIcon, NavItem, NavText } from 'cozy-ui/react'
import { NavLink } from 'react-router-dom'
import { translate } from 'cozy-ui/react/I18n'
import cx from 'classnames'
import Icon from 'cozy-ui/react/Icon'
import PlaylistIcon from '../../assets/icons/icon-playlist.svg'
import AlbumIcon from '../../assets/icons/icon-album.svg'
import ArtistIcon from '../../assets/icons/icon-artist.svg'
import GenreIcon from '../../assets/icons/icon-track.svg'
import styles from 'cozy-ui/react/Nav/styles.styl'
export const LibraryNav = ({ t }) => (
<UINav>
<NavItem>
<NavLink to="/library/playlists" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<NavIcon icon={PlaylistIcon} />
<NavText>{t('Nav.playlists')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/albums" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={AlbumIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.albums')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/artists" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={ArtistIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.artists')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/genres" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={GenreIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.genres')}</NavText>
</NavLink>
</NavItem>
</UINav>
)
// translate() provide t() to use translations (ex: locales/en.json)
export default translate()(LibraryNav)
import React from 'react' import React from 'react'
export const List = () => ( export const List = () => <p>List</p>
<p>Just... Hello world! This is a first hello view</p>
)
export default List export default List
import React from 'react' import React from 'react'
import { Layout, Sidebar } from 'cozy-ui/react'
import { LibraryNav } from './LibraryNav'
export const Playlists = () => ( export const Playlists = () => (
<p>Playlists</p> <Layout>
<Sidebar>
<LibraryNav />
</Sidebar>
</Layout>
) )
export default Playlists export default Playlists
import React from 'react'
import Icon from 'cozy-ui/react/Icon'
import cx from 'classnames'
import { translate } from 'cozy-ui/react/I18n'
import { Nav as UINav, NavItem, NavText, NavIcon } from 'cozy-ui/react'
import { NavLink } from 'react-router-dom'
import LibraryIcon from '../assets/icons/icon-library.svg'
import PlaylistIcon from '../assets/icons/icon-playlist.svg'
import RecentIcon from '../assets/icons/icon-recent.svg'
import styles from 'cozy-ui/react/Nav/styles.styl'
export const Nav = ({ t }) => (
<UINav>
<NavItem>
<NavLink to="/recent" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<NavIcon icon={RecentIcon} />
<NavText>{t('Nav.recent')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/library/playlists" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={LibraryIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.library')}</NavText>
</NavLink>
</NavItem>
<NavItem>
<NavLink to="/parameters" className={styles['c-nav-link']} activeClassName={styles['is-active']}>
<span className={cx(styles['c-nav-icon'])}>
<Icon icon={PlaylistIcon} aria-hidden="true" focusable="false" />
</span>
<NavText>{t('Nav.parameters')}</NavText>
</NavLink>
</NavItem>
</UINav>
)
// translate() provide t() to use translations (ex: locales/en.json)
export default translate()(Nav)
import React from 'react' import React from 'react'
export const Recent = () => ( export const Recent = () => <p>Listen Recently</p>
<p>Listen Recently</p>
)
export default Recent export default Recent
import React from 'react'
import Icon from 'cozy-ui/react/Icon'
import { translate } from 'cozy-ui/react/I18n'
import { NavLink } from 'react-router-dom'
import NavIcon from '../assets/icons/icon-bullet-point.svg'
export const Sidebar = ({ t }) => (
<aside className="o-sidebar">
<nav>
<ul className="c-nav">
<li className="c-nav-item">
<NavLink
to="/recent"
className="c-nav-link"
activeClassName="is-active"
>
<Icon className="c-nav-icon" icon={NavIcon} />
{t('Nav.recent')}
</NavLink>
</li>
<li className="c-nav-item">
<NavLink
to="/playlists"
className="c-nav-link"
activeClassName="is-active"
>
<Icon className="c-nav-icon" icon={NavIcon} />
{t('Nav.playlists')}
</NavLink>
</li>
<li className="c-nav-item">
<NavLink
to="/artists"
className="c-nav-link"
activeClassName="is-active"
>
<Icon className="c-nav-icon" icon={NavIcon} />
{t('Nav.artists')}
</NavLink>
</li>
<li className="c-nav-item">
<NavLink
to="/albums"
className="c-nav-link"
activeClassName="is-active"
>
<Icon className="c-nav-icon" icon={NavIcon} />
{t('Nav.albums')}
</NavLink>
</li>
<li className="c-nav-item">
<NavLink
to="/genres"
className="c-nav-link"
activeClassName="is-active"
>
<Icon className="c-nav-icon" icon={NavIcon} />
{t('Nav.genres')}
</NavLink>
</li>
</ul>
</nav>
</aside>
)
// translate() provide t() to use translations (ex: locales/en.json)
export default translate()(Sidebar)
import { TODOS_DOCTYPE } from './todos' import { PLAYLIST_DOCTYPE } from './playlist'
export const FILES_DOCTYPE = 'io.cozy.files'
// the documents schema, necessary for CozyClient // the documents schema, necessary for CozyClient
export default { export default {
todos: { playlists: {
doctype: TODOS_DOCTYPE, doctype: PLAYLIST_DOCTYPE,
attributes: {}, attributes: {},
relationships: {} relationships: {}
} }
} }
// export all doctypes for the application // export all doctypes for the application
export * from './todos' export * from './playlist'
export const schema = {
files: { doctype: FILES_DOCTYPE },
playlists: { doctype: PLAYLIST_DOCTYPE }
}
export const PLAYLIST_DOCTYPE = 'fr.mobdev.cozymusic.playlists'
// queries for CozyClient
export const playlistQuery = client => client.find(PLAYLIST_DOCTYPE)
export const TODOS_DOCTYPE = 'io.mocks.todos'
// queries for CozyClient
export const todosQuery = client => client.find(TODOS_DOCTYPE)
{ {
"Nav": { "Nav": {
"recent": "Listen Recently", "recent": "Listen Recently",
"playlists": "Playlists", "playlists": "Playlists",
"artists": "Artists", "library": "Library",
"albums": "Albums", "albums" : "Albums",
"genres": "Genres" "genres" : "Genres",
"artists" : "Artists"
} }
} }
...@@ -12,10 +12,7 @@ let appLocale ...@@ -12,10 +12,7 @@ let appLocale
const renderApp = function(client) { const renderApp = function(client) {
const App = require('components/App').default const App = require('components/App').default
render( render(
<I18n <I18n lang={appLocale} dictRequire={appLocale => require(`locales/${appLocale}`)}>
lang={appLocale}
dictRequire={appLocale => require(`locales/${appLocale}`)}
>
<CozyProvider client={client}> <CozyProvider client={client}>
<App /> <App />
</CozyProvider> </CozyProvider>
...@@ -35,20 +32,11 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -35,20 +32,11 @@ document.addEventListener('DOMContentLoaded', () => {
const root = document.querySelector('[role=application]') const root = document.querySelector('[role=application]')
const data = root.dataset const data = root.dataset
const appIcon = getDataOrDefault( const appIcon = getDataOrDefault(data.cozyIconPath, require('../vendor/assets/icon.svg'))
data.cozyIconPath,
require('../vendor/assets/icon.svg')
)
const appNamePrefix = getDataOrDefault( const appNamePrefix = getDataOrDefault(data.cozyAppNamePrefix || require('../../../manifest.webapp').name_prefix, '')
data.cozyAppNamePrefix || require('../../../manifest.webapp').name_prefix,
''
)
const appName = getDataOrDefault( const appName = getDataOrDefault(data.cozyAppName, require('../../../manifest.webapp').name)
data.cozyAppName,
require('../../../manifest.webapp').name
)
appLocale = getDataOrDefault(data.cozyLocale, 'en') appLocale = getDataOrDefault(data.cozyLocale, 'en')
......
# Mobile development documentation
[Cozy Docs](https://cozy.github.io/cozy-docs-v3/en/dev/cordova/)
<?xml version='1.0' encoding='utf-8'?>
<widget id="fr.mobdev.cozymusic" version="0.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>Cozy Music</name>
<description>
A Music application for Cozy.io
</description>
<author email="developer@mob-dev.fr" href="https://mob-dev.fr">
Mob-Dev dev team
</author>
<content src="index.html" />
<plugin name="cordova-plugin-whitelist" spec="1" />
<plugin name="cordova-plugin-customurlscheme" spec="~4.3.0">
<variable name="URL_SCHEME" value="cozymusic" />
</plugin>
<plugin name="cordova-plugin-inappbrowser" spec="1.7.0" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
</platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
</platform>
<engine name="android" spec="^7.1.4" />
</widget>
<!DOCTYPE html>
<html lang="{{.Locale}}">
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/site.webmanifest" crossOrigin="use-credentials">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#297EF2">
<% if (__TARGET__ !== 'mobile') { %>
<link rel="stylesheet" type="text/css" href="//{{.Domain}}/assets/fonts/fonts.css">
<% } %>
<meta name="theme-color" content="#ffffff">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, viewport-fit=cover">
<% _.forEach(htmlWebpackPlugin.files.css, function(file) { %>
<link rel="stylesheet" href="<%- file %>">
<% }); %>
<% _.forEach(htmlWebpackPlugin.files.js, function(file) { %>
<script src="<%- file %>" defer></script>
<% }); %>
<% if (__TARGET__ === 'mobile') { %>
<meta name="format-detection" content="telephone=no">
<script src="cordova.js" defer></script>
<% } else if (__STACK_ASSETS__) { %>
{{.CozyBar}}
<% } %>
</head>
<div
role="application"
data-cozy-token="{{.Token}}"
data-cozy-domain="{{.Domain}}"
data-cozy-locale="{{.Locale}}"
data-cozy-app-name="{{.AppName}}"
data-cozy-app-slug="{{.AppSlug}}"
data-cozy-app-name-prefix="{{.AppNamePrefix}}"
data-cozy-app-editor="{{.AppEditor}}"
data-cozy-icon-path="{{.IconPath}}"
>
/* global cozy */
import 'styles'
import React from 'react'
import CozyClient, { CozyProvider } from 'cozy-client'
import { render } from 'react-dom'
import { I18n } from 'cozy-ui/react/I18n'
import { schema, FILES_DOCTYPE, PLAYLIST_DOCTYPE } from '../../doctypes'
export const getLang = () => (navigator && navigator.language ? navigator.language.slice(0, 2) : 'en')
let appLocale
const renderApp = function(client) {
const App = require('components/App').default
render(
<I18n lang={appLocale} dictRequire={appLocale => require(`locales/${appLocale}`)}>
<CozyProvider client={client}>
<App />
</CozyProvider>
</I18n>,
document.querySelector('[role=application]')
)
}
// return a defaultData if the template hasn't been replaced by cozy-stack
const getDataOrDefault = function(toTest, defaultData) {
const templateRegex = /^\{\{\.[a-zA-Z]*\}\}$/ // {{.Example}}
return templateRegex.test(toTest) ? defaultData : toTest
}
// initial rendering of the application
document.addEventListener('DOMContentLoaded', () => {
const root = document.querySelector('[role=application]')
const data = root.dataset
appLocale = getDataOrDefault(data.cozyLocale, 'en')
// initialize the client to interact with the cozy stack
const client = new CozyClient({
uri: 'https://schoumi.mycozy.cloud',
oauth: {
redirectURI: 'cozymusic://auth',
softwareID: 'fr.mobdev.cozymusic',
softwareVersion: '0.1.0',
clientName: 'CozyMusic',
clientKind: 'mobile',
clientURI: 'https://github.com/Schoumi/cozy-music',
logoURI: 'https://github.com/cozy/cozy-drive/raw/master/targets/drive/vendor/assets/oauth-app-icon.png',
policyURI: 'https://files.cozycloud.cc/cgu.pdf'
},
scope: ['io.cozy.files:GET:POST', 'fr.mobdev.cozymusic.playlist'],
offline: { doctypes: [FILES_DOCTYPE, PLAYLIST_DOCTYPE] },
schema
})
initClient(client)
// initialize the bar, common of all applications, it allows
// platform features like apps navigation without doing anything
initBar(client)
renderApp(client)
})
const getToken = async () => {
const credentials = await cozy.client.authorize()
return credentials.token.accessToken
}
const getTokenWithNoException = async () => {
try {
return await getToken()
} catch (_) {
return null
}
}