mirror of
https://github.com/standardnotes/mobile.git
synced 2026-04-20 06:09:11 -04:00
Themes, handle hosted_url, plus mobile specific flags
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ export default class AuthSection extends AbstractComponent {
|
||||
autoFocus={true}
|
||||
underlineColorAndroid={'transparent'}
|
||||
placeholderTextColor={GlobalStyles.constants().mainDimColor}
|
||||
onSubmitEditing={this.onSignInPress}
|
||||
/>
|
||||
</SectionedTableCell>
|
||||
</View>
|
||||
|
||||
@@ -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
126
src/models/app/component.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user