Skip to content
This repository has been archived by the owner on Jun 15, 2022. It is now read-only.

Commit

Permalink
feature: WIP themes
Browse files Browse the repository at this point in the history
  • Loading branch information
radko93 committed Aug 19, 2020
1 parent 9d9bbc5 commit dfcab67
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 142 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -53,7 +53,7 @@
"react-native-webview": "^10.7.0",
"react-navigation-header-buttons": "^5.0.2",
"sn-textview": "standardnotes/sn-textview#f42f0bf",
"snjs": "standardnotes/snjs#84b0403",
"snjs": "standardnotes/snjs#27688ba",
"standard-notes-rn": "standardnotes/standard-notes-rn",
"styled-components": "^5.1.1"
},
Expand Down
39 changes: 30 additions & 9 deletions src/App.tsx
Expand Up @@ -29,6 +29,7 @@ import { MainSideMenu } from '@Screens/SideMenu/MainSideMenu';
import { NoteSideMenu } from '@Screens/SideMenu/NoteSideMenu';
import { ICON_CHECKMARK, ICON_CLOSE, ICON_MENU } from '@Style/icons';
import { StyleKit, StyleKitContext } from '@Style/StyleKit';
import { StyleKitTheme } from '@Style/Themes/styled-components';
import { getDefaultDrawerWidth } from '@Style/Util/getDefaultDraerWidth';
import React, {
useCallback,
Expand Down Expand Up @@ -420,35 +421,55 @@ const AppComponent: React.FC<{
env: 'prod' | 'dev';
}> = ({ application, env }) => {
const [ready, setReady] = useState(false);
const styleKit = useRef<StyleKit | undefined>(undefined);
const styleKit = useRef<StyleKit>();
const [activeTheme, setActiveTheme] = useState<StyleKitTheme | undefined>();

const setStyleKitRef = useCallback((node: StyleKit | undefined) => {
if (node) {
node.addThemeChangeObserver(() => {
setActiveTheme(node.theme);
});
}

// Save a reference to the node
styleKit.current = node;
}, []);

useEffect(() => {
let styleKitInstance: StyleKit;
const loadApplication = async () => {
await application?.prepareForLaunch({
receiveChallenge: async challenge => {
application!.promptForChallenge(challenge);
},
});
styleKit.current = new StyleKit(application);
await styleKit.current.init();
styleKitInstance = new StyleKit(application);
await styleKitInstance.init();
setStyleKitRef(styleKitInstance);
setActiveTheme(styleKitInstance.theme);
setReady(true);
};
setReady(false);
loadApplication();
}, [application, env]);

if (!ready || !styleKit.current) {
return () => {
styleKitInstance?.deinit();
setStyleKitRef(undefined);
};
}, [application, env, setStyleKitRef]);

if (!ready || !styleKit.current || !activeTheme) {
return null;
}
// TODO: better modes support

return (
<NavigationContainer
theme={{
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: styleKit.current.theme!.stylekitBackgroundColor,
border: styleKit.current.theme!.stylekitBorderColor,
background: activeTheme.stylekitBackgroundColor,
border: activeTheme.stylekitBorderColor,
},
}}
onReady={() => {
Expand All @@ -459,7 +480,7 @@ const AppComponent: React.FC<{
<StatusBar translucent />
{styleKit.current && (
<>
<ThemeProvider theme={styleKit.current.theme!}>
<ThemeProvider theme={activeTheme}>
<ActionSheetProvider>
<StyleKitContext.Provider value={styleKit.current}>
<MainStackComponent env={env} />
Expand Down
1 change: 1 addition & 0 deletions src/screens/Settings/Sections/CompanySection.tsx
Expand Up @@ -65,6 +65,7 @@ export const CompanySection = (props: Props) => {
<SectionHeader title={props.title} />

<ButtonCell
first
leftAligned={true}
title="Help"
onPress={() => openUrl('help')}
Expand Down
108 changes: 96 additions & 12 deletions src/screens/SideMenu/MainSideMenu.tsx
Expand Up @@ -3,9 +3,11 @@ import { useNavigation } from '@react-navigation/native';
import { ApplicationContext } from '@Root/ApplicationContext';
import { SCREEN_SETTINGS } from '@Screens/screens';
import { ICON_SETTINGS } from '@Style/icons';
import { StyleKit } from '@Style/StyleKit';
import { StyleKit, StyleKitContext, ThemeContent } from '@Style/StyleKit';
import _ from 'lodash';
import React, {
Fragment,
useCallback,
useContext,
useEffect,
useMemo,
Expand All @@ -15,7 +17,7 @@ import { Platform } from 'react-native';
import FAB from 'react-native-fab';
import DrawerLayout from 'react-native-gesture-handler/DrawerLayout';
import Icon from 'react-native-vector-icons/Ionicons';
import { ContentType, SNTag, SNTheme } from 'snjs';
import { ContentType, SNTag, SNTheme, ThemeMutator } from 'snjs';
import { ThemeContext } from 'styled-components/native';
import {
FirstSafeAreaView,
Expand All @@ -33,6 +35,7 @@ type Props = {
export const MainSideMenu = ({ drawerRef }: Props): JSX.Element => {
// Context
const theme = useContext(ThemeContext);
const styleKit = useContext(StyleKitContext);
const application = useContext(ApplicationContext);
const navigation = useNavigation();

Expand All @@ -54,7 +57,41 @@ export const MainSideMenu = ({ drawerRef }: Props): JSX.Element => {
return removeTagChangeObserver;
});

const onThemeSelect = (_theme: SNTheme) => {};
const onSystemThemeSelect = useCallback(
async (selectedTheme: ThemeContent) => {
const oldTheme = application!.findItem(styleKit!.activeThemeId!) as
| SNTheme
| undefined;

styleKit?.activateSystemTheme(selectedTheme.uuid);
if (oldTheme?.isTheme() && oldTheme.isMobileActive()) {
await application?.changeAndSaveItem(oldTheme.uuid, mutator => {
const themeMutator = mutator as ThemeMutator;
themeMutator.setMobileActive(false);
});
}
},
[application, styleKit]
);

const onThemeSelect = useCallback(
async (selectedTheme: SNTheme) => {
if (!selectedTheme.isMobileActive()) {
await application?.changeItem(selectedTheme.uuid, mutator => {
const themeMutator = mutator as ThemeMutator;
themeMutator.setMobileActive(true);
});
if (application!.findItem(styleKit!.activeThemeId!)) {
await application?.changeItem(styleKit!.activeThemeId!, mutator => {
const themeMutator = mutator as ThemeMutator;
themeMutator.setMobileActive(false);
});
}
await application?.sync();
}
},
[application, styleKit]
);

useEffect(() => {
const unsubscribeStreamThemes = application?.streamItems(
Expand All @@ -68,18 +105,65 @@ export const MainSideMenu = ({ drawerRef }: Props): JSX.Element => {
return unsubscribeStreamThemes;
}, [application]);

const iconDescriptorForTheme = (currentTheme: SNTheme | ThemeContent) => {
const desc = {
type: 'circle',
side: 'right' as 'right',
};

const dockIcon =
currentTheme.package_info && currentTheme.package_info.dock_icon;

if (dockIcon && dockIcon.type === 'circle') {
_.merge(desc, {
backgroundColor: dockIcon.background_color,
borderColor: dockIcon.border_color,
});
} else {
_.merge(desc, {
backgroundColor: theme.stylekitInfoColor,
borderColor: theme.stylekitInfoColor,
});
}

return desc;
};

const themeOptions = useMemo(() => {
let options: SideMenuOption[] = themes
.filter(el => !el.errorDecrypting)
.map(mapTheme => ({
text: mapTheme.name,
key: mapTheme.uuid,
dimmed: mapTheme.getNotAvailOnMobile(),
onSelect: () => onThemeSelect(mapTheme),
}));
const options: SideMenuOption[] = styleKit!
.systemThemes()
.map(systemTheme => ({
text: systemTheme?.name,
key: systemTheme?.uuid,
iconDesc: iconDescriptorForTheme(systemTheme),
dimmed: false,
onSelect: () => onSystemThemeSelect(systemTheme),
selected: styleKit!.activeThemeId === systemTheme?.uuid,
}))
.concat(
themes
.filter(el => !el.errorDecrypting)
.sort((a, b) => a.name.localeCompare(b.name))
.map(mapTheme => ({
text: mapTheme.name,
key: mapTheme.uuid,
iconDesc: iconDescriptorForTheme(mapTheme),
dimmed: mapTheme.getNotAvailOnMobile(),
onSelect: () => onThemeSelect(mapTheme),
selected: styleKit!.activeThemeId === mapTheme.uuid,
}))
);

return options;
}, [themes]);
// We want to also track activeThemeId
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
styleKit,
styleKit?.activeThemeId,
themes,
onSystemThemeSelect,
onThemeSelect,
]);

const onTagSelect = async (tag: SNTag) => {
if (tag.conflictOf) {
Expand Down
15 changes: 1 addition & 14 deletions src/screens/SideMenu/TagSelectionList.tsx
Expand Up @@ -34,20 +34,7 @@ export const TagSelectionList = (props: Props): JSX.Element => {
if (props.contentType === ContentType.SmartTag) {
setTags(application!.getSmartTags());
} else {
setTags(
(application!.getItems(props.contentType) as SNTag[]).sort((a, b) => {
if (!a.title) {
return -1;
}
if (!b.title) {
return 1;
}
if (!a.title && !b.title) {
return 0;
}
return a.title.localeCompare(b.title);
})
);
setTags(application!.getDisplayableItems(props.contentType) as SNTag[]);
}
}, [application, props.contentType]);

Expand Down

0 comments on commit dfcab67

Please sign in to comment.