Themes, handle hosted_url, plus mobile specific flags

This commit is contained in:
Mo Bitar
2018-01-23 13:49:54 -06:00
parent 3f52d4f1d3
commit f3f59fce8d
5 changed files with 201 additions and 60 deletions

View File

@@ -26,19 +26,23 @@ export default class GlobalStyles {
// Get the active theme from storage rather than waiting for local database to load
return Storage.getItem("activeTheme").then(function(theme) {
if(theme) {
// JSON stringified content is generic and includes all items property at time of stringification
// So we parse it, then set content to itself, so that the mapping can be handled correctly.
theme = JSON.parse(theme);
theme.content = theme;
theme = new Theme(theme);
theme.isSwapIn = true;
var constants = _.merge(this.defaultConstants(), theme.mobileRules.constants);
var rules = _.merge(this.defaultRules(constants), theme.mobileRules.rules);
this.setStyles(rules, constants, theme.mobileRules.statusBar);
var constants = _.merge(this.defaultConstants(), theme.getMobileRules().constants);
var rules = _.merge(this.defaultRules(constants), theme.getMobileRules().rules);
this.setStyles(rules, constants, theme.getMobileRules().statusBar);
this.activeTheme = theme;
} else {
var theme = this.systemTheme();
theme.active = true;
theme.setMobileActive(true);
this.activeTheme = theme;
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, theme.mobileRules.statusBar);
this.setStyles(this.defaultRules(constants), constants, theme.getMobileRules().statusBar);
}
}.bind(this));
}
@@ -50,7 +54,7 @@ export default class GlobalStyles {
if(this.activeTheme && this.activeTheme.isSwapIn) {
this.activeTheme.isSwapIn = false;
this.activeTheme = _.find(this.themes(), {uuid: this.activeTheme.uuid});
this.activeTheme.active = true;
this.activeTheme.setMobileActive(true);
}
}.bind(this));
}
@@ -81,11 +85,11 @@ export default class GlobalStyles {
// want to use the defaults, but instead just look at the activeTheme. Because default platform values only apply
// to the default theme
var platform = Platform.OS == "android" ? "Android" : "IOS";
if(!this.get().activeTheme.mobileRules) {
if(!this.get().activeTheme.hasMobileRules()) {
return null;
}
var platformValue = this.get().activeTheme.mobileRules.constants[key+platform];
var platformValue = this.get().activeTheme.getMobileRules().constants[key+platform];
if(platformValue) {
return platformValue;
@@ -102,14 +106,14 @@ export default class GlobalStyles {
this._systemTheme = new Theme({
name: "Default",
default: true,
uuid: 0,
mobileRules: {
name: "Default",
rules: this.defaultRules(constants),
constants: constants,
statusBar: Platform.OS == "android" ? "light-content" : "dark-content"
}
uuid: 0
});
this._systemTheme.setMobileRules({
name: "Default",
rules: this.defaultRules(constants),
constants: constants,
statusBar: Platform.OS == "android" ? "light-content" : "dark-content"
})
return this._systemTheme;
}
@@ -123,16 +127,18 @@ export default class GlobalStyles {
activateTheme(theme, writeToStorage = true) {
if(this.activeTheme) {
this.activeTheme.active = false;
this.activeTheme.setMobileActive(false);
this.activeTheme.setDirty(true);
}
var run = () => {
var constants = _.merge(this.defaultConstants(), theme.mobileRules.constants);
var rules = _.merge(this.defaultRules(constants), theme.mobileRules.rules);
this.setStyles(rules, constants, theme.mobileRules.statusBar);
var constants = _.merge(this.defaultConstants(), theme.getMobileRules().constants);
var rules = _.merge(this.defaultRules(constants), theme.getMobileRules().rules);
this.setStyles(rules, constants, theme.getMobileRules().statusBar);
this.activeTheme = theme;
theme.active = true;
theme.setMobileActive(true);
theme.setDirty(true);
if(theme.default) {
Storage.removeItem("activeTheme");
@@ -143,11 +149,12 @@ export default class GlobalStyles {
App.get().reload();
}
if(!theme.mobileRules) {
if(!theme.hasMobileRules()) {
this.downloadTheme(theme, function(){
if(theme.notAvailableOnMobile) {
if(theme.getNotAvailOnMobile()) {
Alert.alert("Not Available", "This theme is not available on mobile.");
} else {
Sync.getInstance().sync();
run();
}
});
@@ -158,8 +165,8 @@ export default class GlobalStyles {
async downloadTheme(theme, callback) {
let errorBlock = (error) => {
if(!theme.notAvailableOnMobile) {
theme.notAvailableOnMobile = true;
if(!theme.getNotAvailOnMobile()) {
theme.setNotAvailOnMobile(true);
theme.setDirty(true);
}
@@ -168,17 +175,17 @@ export default class GlobalStyles {
console.error("Theme download error", error);
}
if(!theme.url) {
var url = theme.url;
if(!url) {
errorBlock(null);
return;
}
var url;
if(theme.url.includes("?")) {
url = theme.url.replace("?", ".json?");
if(url.includes("?")) {
url = url.replace("?", ".json?");
} else {
url = theme.url + ".json";
url = url + ".json";
}
if(App.isAndroid && url.includes("localhost")) {
@@ -187,13 +194,13 @@ export default class GlobalStyles {
return Server.getInstance().getAbsolute(url, {}, function(response){
// success
if(response !== theme.mobileRules) {
theme.mobileRules = response;
if(response !== theme.getMobileRules()) {
theme.setMobileRules(response);
theme.setDirty(true);
}
if(theme.notAvailableOnMobile) {
theme.notAvailableOnMobile = false;
if(theme.getNotAvailOnMobile()) {
theme.setNotAvailOnMobile(false);
theme.setDirty(true);
}

View File

@@ -98,6 +98,7 @@ export default class AuthSection extends AbstractComponent {
autoFocus={true}
underlineColorAndroid={'transparent'}
placeholderTextColor={GlobalStyles.constants().mainDimColor}
onSubmitEditing={this.onSignInPress}
/>
</SectionedTableCell>
</View>

View File

@@ -23,8 +23,8 @@ export default class ThemesSection extends Component {
text={theme.name}
key={theme.uuid}
first={i == 0}
selected={() => {return theme.active}}
dimmed={theme.notAvailableOnMobile}
selected={() => {return theme.isMobileActive()}}
dimmed={theme.getNotAvailOnMobile()}
last={i == this.props.themes.length - 1 && this.props.themes.length > 1}
/>
)

126
src/models/app/component.js Normal file
View File

@@ -0,0 +1,126 @@
import Item from "../api/item"
var _ = require('lodash')
export default class Component extends Item {
constructor(json_obj) {
super(json_obj);
if(!this.componentData) {
this.componentData = {};
}
if(!this.disassociatedItemIds) {
this.disassociatedItemIds = [];
}
if(!this.associatedItemIds) {
this.associatedItemIds = [];
}
}
mapContentToLocalProperties(content) {
super.mapContentToLocalProperties(content)
/* Legacy */
this.url = content.url;
/* New */
this.local_url = content.local_url;
this.hosted_url = content.hosted_url;
this.offlineOnly = content.offlineOnly;
if(content.valid_until) {
this.valid_until = new Date(content.valid_until);
}
this.name = content.name;
this.autoupdateDisabled = content.autoupdateDisabled;
this.package_info = content.package_info;
// the location in the view this component is located in. Valid values are currently tags-list, note-tags, and editor-stack`
this.area = content.area;
this.permissions = content.permissions;
this.active = content.active;
// custom data that a component can store in itself
this.componentData = content.componentData || {};
// items that have requested a component to be disabled in its context
this.disassociatedItemIds = content.disassociatedItemIds || [];
// items that have requested a component to be enabled in its context
this.associatedItemIds = content.associatedItemIds || [];
}
structureParams() {
var params = {
url: this.url,
hosted_url: this.hosted_url,
local_url: this.local_url,
valid_until: this.valid_until,
offlineOnly: this.offlineOnly,
name: this.name,
area: this.area,
package_info: this.package_info,
permissions: this.permissions,
active: this.active,
autoupdateDisabled: this.autoupdateDisabled,
componentData: this.componentData,
disassociatedItemIds: this.disassociatedItemIds,
associatedItemIds: this.associatedItemIds,
};
_.merge(params, super.structureParams());
return params;
}
get content_type() {
return "SN|Component";
}
isEditor() {
return this.area == "editor-editor";
}
isDefaultEditor() {
return this.getAppDataItem("defaultEditor") == true;
}
setLastSize(size) {
this.setAppDataItem("lastSize", size);
}
getLastSize() {
return this.getAppDataItem("lastSize");
}
keysToIgnoreWhenCheckingContentEquality() {
return ["active"].concat(super.keysToIgnoreWhenCheckingContentEquality());
}
/*
An associative component depends on being explicitly activated for a given item, compared to a dissaciative component,
which is enabled by default in areas unrelated to a certain item.
*/
static associativeAreas() {
return ["editor-editor"];
}
isAssociative() {
return Component.associativeAreas().includes(this.area);
}
associateWithItem(item) {
this.associatedItemIds.push(item.uuid);
}
isExplicitlyEnabledForItem(item) {
return this.associatedItemIds.indexOf(item.uuid) !== -1;
}
isExplicitlyDisabledForItem(item) {
return this.disassociatedItemIds.indexOf(item.uuid) !== -1;
}
}

View File

@@ -1,34 +1,12 @@
import Item from "../api/item"
import Component from "./component"
var _ = require('lodash')
export default class Theme extends Item {
export default class Theme extends Component {
constructor(json_obj) {
super(json_obj);
}
mapContentToLocalProperties(contentObject) {
super.mapContentToLocalProperties(contentObject)
this.url = contentObject.url;
this.hosted_url = contentObject.hosted_url;
this.name = contentObject.name;
this.mobileRules = contentObject.mobileRules;
this.notAvailableOnMobile = contentObject.notAvailableOnMobile;
}
structureParams() {
var params = {
url: this.url,
name: this.name,
hosted_url: this.hosted_url,
mobileRules: this.mobileRules,
notAvailableOnMobile: this.notAvailableOnMobile
};
_.merge(params, super.structureParams());
return params;
}
get content_type() {
return "SN|Theme";
}
@@ -36,4 +14,33 @@ export default class Theme extends Item {
get displayName() {
return "Theme";
}
setMobileRules(rules) {
this.setAppDataItem("mobileRules", rules);
}
getMobileRules() {
return this.getAppDataItem("mobileRules") || {constants: {}, rules: {}};
}
// Same as getMobileRules but without default value
hasMobileRules() {
return this.getAppDataItem("mobileRules");
}
setNotAvailOnMobile(na) {
this.setAppDataItem("notAvailableOnMobile", na);
}
getNotAvailOnMobile() {
return this.getAppDataItem("notAvailableOnMobile");
}
setMobileActive(active) {
this.setAppDataItem("mobileActive", active);
}
isMobileActive() {
return this.getAppDataItem("mobileActive");
}
}