feat: create addon tab, translation support for stats tab, fixes etc

This commit is contained in:
David Ralph
2021-08-14 17:23:54 +01:00
parent b8c793741f
commit 1a8bb69288
16 changed files with 326 additions and 13 deletions

View File

@@ -0,0 +1,155 @@
import React from 'react';
import FileUpload from '../../settings/FileUpload';
import SettingsFunctions from '../../../../../modules/helpers/settings/modals';
import { toast } from 'react-toastify';
export default class Create extends React.PureComponent {
constructor() {
super();
this.state = {
currentTab: 1,
addonMetadata: {
name: '',
description: '',
type: '',
version: '',
author: '',
icon_url: '',
screenshot_url: '',
},
addonData: ''
};
}
changeTab(tab, type) {
if (type) {
return this.setState({
currentTab: tab,
addonMetadata: {
type: type
}
});
}
this.setState({
currentTab: tab
});
}
importSettings() {
let settings = {};
Object.keys(localStorage).forEach((key) => {
if (key === 'statsData' || key === 'firstRun' || key === 'showWelcome' || key === 'language' || key === 'installed' || key === 'stats') {
return;
}
settings[key] = localStorage.getItem(key);
});
this.setState({
addonData: settings
});
toast('Imported settings!');
}
uploadSettings(input) {
let settings = {};
Object.keys(input).forEach((key) => {
if (key === 'statsData' || key === 'firstRun' || key === 'showWelcome' || key === 'language' || key === 'installed' || key === 'stats') {
return;
}
settings[key] = localStorage.getItem(key);
});
this.setState({
addonData: settings
});
toast('Imported settings!');
}
downloadAddon() {
SettingsFunctions.saveFile({
name: this.state.addonMetadata.name,
description: this.state.addonMetadata.description,
type: this.state.addonMetadata.type,
version: this.state.addonMetadata.version,
author: this.state.addonMetadata.author,
icon_url: this.state.addonMetadata.icon_url,
screenshot_url: this.state.addonMetadata.screenshot_url,
settings: this.state.addonData
}, this.state.addonMetadata.name + '.json');
}
render() {
let tabContent;
const chooseType = (
<>
<h3>Type</h3>
<button onClick={() => this.changeTab(2, 'settings')} className='uploadbg'>Settings</button>
</>
);
const writeDescription = (
<>
<h3>Information</h3>
<p>Name</p>
<input type='text' value={this.state.addonMetadata.name} onInput={(e) => this.setState({ addonMetadata: { name: e.target.value }})}/>
<p>Version</p>
<input type='text' value={this.state.addonMetadata.version} onInput={(e) => this.setState({ addonMetadata: { version: e.target.value }})}/>
<p>Author</p>
<input type='text' value={this.state.addonMetadata.author} onInput={(e) => this.setState({ addonMetadata: { author: e.target.value }})}/>
<p>Icon URL</p>
<input type='text' value={this.state.addonMetadata.icon_url} onInput={(e) => this.setState({ addonMetadata: { icon_url: e.target.value }})}/>
<p>Screenshot URL</p>
<input type='text' value={this.state.addonMetadata.screenshot_url} onInput={(e) => this.setState({ addonMetadata: { screenshot_url: e.target.value }})}/>
<p>Description</p>
<textarea className='settingsTextarea' value={this.state.addonMetadata.description} onInput={(e) => this.setState({ addonMetadata: { description: e.target.value }})}></textarea>
<br/>
<button onClick={() => this.changeTab(1)} className='uploadbg' style={{ marginRight: '10px' }}>Back</button>
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg'>Next</button>
</>
);
// settings
const importSettings = (
<>
<h3>Import Settings</h3>
<p onClick={() => this.importSettings()} className='addToMue'>Import current setup</p>
<br/><br/><br/>
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => this.uploadSettings(JSON.parse(e.target.result))} />
<p className='addToMue' style={{ position: 'absolute' }} onClick={() => document.getElementById('file-input').click()}>Upload JSON</p>
<br/><br/>
<button onClick={() => this.changeTab(2, 'settings')} className='uploadbg' style={{ marginRight: '10px' }}>Back</button>
<button onClick={() => this.changeTab(3)} className='uploadbg'>Next</button>
</>
);
const downloadAddon = (
<>
<h3>Finish</h3>
<button onClick={() => this.downloadAddon()} className='upload'>Download Add-on</button>
<br/><br/>
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg' style={{ marginRight: '10px' }}>Back</button>
</>
);
switch (this.state.currentTab) {
case 2: tabContent = writeDescription; break;
case 'settings': tabContent = importSettings; break;
case 3: tabContent = downloadAddon; break;
default: tabContent = chooseType;
}
return (
<>
<h2>Create Add-on</h2>
{tabContent}
</>
);
}
}

View File

@@ -10,6 +10,7 @@ export default class Stats extends React.PureComponent {
this.state = {
stats: JSON.parse(localStorage.getItem('statsData')) || {}
};
this.language = window.language.modals.main.settings.sections.stats;
}
componentDidMount() {
@@ -31,23 +32,23 @@ export default class Stats extends React.PureComponent {
return (
<>
<h2>Notice</h2>
<p>You need to enable usage data in order to use this feature</p>
<Switch name='stats' text='Usage Stats' category='stats'/>
<p>{this.language.warning}</p>
<Switch name='stats' text={this.language.usage} category='stats'/>
</>
);
}
return (
<>
<h2>Stats</h2>
<p>Tabs opened: {this.state.stats['tabs-opened'] || 0}</p>
<p>Backgrounds favourited: {this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}</p>
<p>Backgrounds downloaded: {this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}</p>
<p>Quotes favourited: {this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}</p>
<p>Quick links added: {this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}</p>
<p>Settings changed: {this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}</p>
<p>Add-ons installed: {this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}</p>
<Switch name='stats' text='Usage Stats' category='stats'/>
<h2>{this.language.title}</h2>
<p>{this.language.sections.tabs_opened}: {this.state.stats['tabs-opened'] || 0}</p>
<p>{this.language.sections.backgrounds_favourited}: {this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}</p>
<p>{this.language.sections.backgrounds_downloaded}: {this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}</p>
<p>{this.language.sections.quotes_favourited}: {this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}</p>
<p>{this.language.sections.quicklinks_added}: {this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}</p>
<p>{this.language.sections.settings_changed}: {this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}</p>
<p>{this.language.sections.addons_installed}: {this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}</p>
<Switch name='stats' text={this.language.usage} category='stats'/>
<p>Turning this off will clear your statistics locally, but will not delete the anonymous data posted to umami.</p>
</>
);

View File

@@ -1,5 +1,6 @@
import Added from '../marketplace/sections/Added';
import Sideload from '../marketplace/sections/Sideload';
import Create from '../marketplace/sections/Create';
import Tabs from './backend/Tabs';
@@ -10,6 +11,7 @@ export default function Addons() {
<Tabs>
<div label={addons.added} name='added'><Added/></div>
<div label={addons.sideload} name='sideload'><Sideload/></div>
<div label='Create' name='create'><Create/></div>
</Tabs>
);
}

View File

@@ -20,10 +20,12 @@ import Order from '@material-ui/icons/List';
import Weather from '@material-ui/icons/CloudOutlined';
import Advanced from '@material-ui/icons/SettingsOutlined';
import QuickLinks from '@material-ui/icons/Link';
import Stats from '@material-ui/icons/AssessmentOutlined';
// Addons
import Sideload from '@material-ui/icons/Code';
import Added from '@material-ui/icons/AddCircleOutline';
import Create from '@material-ui/icons/CreateNewFolderOutlined';
function Tab(props) {
let className = 'tab-list-item';
@@ -60,6 +62,7 @@ function Tab(props) {
case settings.order.title: icon = <Order/>; break;
case settings.language.title: icon = <Language/>; divider = true; break;
case settings.advanced.title: icon = <Advanced/>; break;
case settings.stats.title: icon = <Stats/>; break;
case settings.experimental.title: icon = <Experimental/>; divider = true; break;
case settings.changelog: icon = <Changelog/>; break;
case settings.about.title: icon = <About/>; break;
@@ -67,6 +70,7 @@ function Tab(props) {
// Addons
case addons.added: icon = <Added/>; break;
case addons.sideload: icon = <Sideload/>; break;
case 'Create': icon = <Create/>; break;
// Marketplace
case marketplace.photo_packs: icon = <Background/>; break;

View File

@@ -54,6 +54,7 @@ export default class WelcomeSections extends React.PureComponent {
let settings = [];
const data = JSON.parse(e.target.result);
Object.keys(data).forEach((setting) => {
// language and theme already shown, the others are only used internally
if (setting === 'language' || setting === 'theme'|| setting === 'firstRun' || setting === 'showWelcome' || setting === 'showReminder') {
return;
}
@@ -129,7 +130,7 @@ export default class WelcomeSections extends React.PureComponent {
</>
);
const { appearance, advanced, background, quicklinks } = window.language.modals.main.settings.sections;
const { appearance, advanced, background, quicklinks, stats } = window.language.modals.main.settings.sections;
const languageSettings = window.language.modals.main.settings.sections.language;
const theme = (
@@ -181,6 +182,8 @@ export default class WelcomeSections extends React.PureComponent {
<Checkbox name='quicklinksddgProxy' text={background.ddg_image_proxy + ' (' + quicklinks.title + ')'}/>
<Checkbox name='ddgProxy' text={background.ddg_image_proxy + ' (' + background.title + ')'}/>
<p>{language.sections.privacy.ddg_proxy_description}</p>
<Checkbox name='stats' text={stats.usage}/>
<p>{language.sections.privacy.stats_description}</p>
<h3 className='quicktip'>{language.sections.privacy.links.title}</h3>
<a className='privacy' href={window.constants.PRIVACY_URL} target='_blank' rel='noopener noreferrer'>{language.sections.privacy.links.privacy_policy}</a>
<br/><br/>