feat: new widgets on android (#7311)

- Added a new widget on android that allows you to put a note on your home screen.
- Added a new widget on android that allows you to see upcoming reminders on home screen
- Fixed new note widget freezing
This commit is contained in:
Ammar Ahmed
2025-01-20 17:17:01 +05:00
committed by GitHub
parent aa993a2fce
commit a13cbadd44
105 changed files with 1758 additions and 356 deletions

View File

@@ -32,12 +32,14 @@ import { withErrorBoundry } from "./components/exception-handler";
import GlobalSafeAreaProvider from "./components/globalsafearea";
import { useAppEvents } from "./hooks/use-app-events";
import { ApplicationHolder } from "./navigation";
import { NotePreviewConfigure } from "./screens/note-preview-configure";
import { themeTrpcClient } from "./screens/settings/theme-selector";
import Notifications from "./services/notifications";
import SettingsService from "./services/settings";
import { TipManager } from "./services/tip-manager";
import { useThemeStore } from "./stores/use-theme-store";
import { useUserStore } from "./stores/use-user-store";
import { IntentService } from "./services/intent";
I18nManager.allowRTL(false);
I18nManager.forceRTL(false);
@@ -47,7 +49,8 @@ if (appLockEnabled || appLockMode !== "none") {
useUserStore.getState().lockApp(true);
}
const App = () => {
IntentService.onLaunch();
const App = (props: { configureMode: "note-preview" }) => {
useAppEvents();
//@ts-ignore
globalThis["IS_MAIN_APP_RUNNING"] = true;
@@ -61,6 +64,7 @@ const App = () => {
TipManager.init();
}, 100);
}, []);
return (
<View
style={{
@@ -90,7 +94,11 @@ const App = () => {
width: "100%"
}}
>
{props.configureMode === "note-preview" ? (
<NotePreviewConfigure />
) : (
<ApplicationHolder />
)}
</GestureHandlerRootView>
<AppLockedOverlay />
</View>
@@ -103,8 +111,8 @@ let currTheme =
: SettingsService.getProperty("lighTheme");
useThemeEngineStore.getState().setTheme(currTheme);
export const withTheme = (Element: () => JSX.Element) => {
return function AppWithThemeProvider() {
export const withTheme = (Element: (props: any) => JSX.Element) => {
return function AppWithThemeProvider(props: any) {
const [colorScheme, darkTheme, lightTheme] = useThemeStore((state) => [
state.colorScheme,
state.darkTheme,
@@ -123,13 +131,14 @@ export const withTheme = (Element: () => JSX.Element) => {
})
.then((theme) => {
if (theme) {
console.log(theme.version, "theme updated");
theme.colorScheme === "dark"
? useThemeStore.getState().setDarkTheme(theme)
: useThemeStore.getState().setLightTheme(theme);
}
})
.catch(console.log);
.catch(() => {
/* empty */
});
}, 1000);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -144,7 +153,7 @@ export const withTheme = (Element: () => JSX.Element) => {
return (
<I18nProvider i18n={i18n}>
<Element />
<Element {...props} />
</I18nProvider>
);
};

View File

@@ -126,7 +126,6 @@ export async function setAppLockVerificationCipher(appLockPassword: string) {
DatabaseLogger.info("setAppLockVerificationCipher");
} catch (e) {
DatabaseLogger.error(e);
console.log(e);
}
}
@@ -310,7 +309,6 @@ export async function getCryptoKey() {
return key;
} catch (e) {
console.log("getCryptoKey", e);
DatabaseLogger.error(e);
}
}

View File

@@ -39,8 +39,6 @@ export async function setupDatabase(password?: string) {
const key = await getDatabaseKey(password);
if (!key) throw new Error(strings.databaseSetupFailed());
console.log("Opening database with key:", !!key);
database.host({
API_HOST: "https://api.notesnook.com",
AUTH_HOST: "https://auth.streetwriters.co",

View File

@@ -27,13 +27,9 @@ import RNFetchBlob from "react-native-blob-util";
*/
export async function compressToBase64(path, type) {
const { width: screenWidth, scale } = Dimensions.get("window");
console.log("COMPRESSING TO BASE64...");
return new Promise((resolve) => {
console.log(path, "image path...");
Image.getSize(path, async (width) => {
console.log("image width", width);
const response = await ImageResizer.createResizedImage(
path,
screenWidth * scale,
@@ -55,10 +51,12 @@ export async function compressToBase64(path, type) {
: response.uri,
"base64"
);
RNFetchBlob.fs.unlink(path.replace("file://", "")).catch(console.log);
RNFetchBlob.fs
.unlink(response.uri.replace("file://", ""))
.catch(console.log);
RNFetchBlob.fs.unlink(path.replace("file://", "")).catch(() => {
/* empty */
});
RNFetchBlob.fs.unlink(response.uri.replace("file://", "")).catch(() => {
/* empty */
});
resolve(base64);
});
@@ -80,6 +78,8 @@ export async function compressToFile(path, type) {
onlyScaleDown: true
}
);
RNFetchBlob.fs.unlink(path.replace("file://", "")).catch(console.log);
RNFetchBlob.fs.unlink(path.replace("file://", "")).catch(() => {
/* empty */
});
return response.uri;
}

View File

@@ -83,7 +83,9 @@ export async function downloadAttachments(attachmentIds: string[]) {
const isCancelled = () => {
if (useAttachmentStore.getState().downloading?.[groupId]?.canceled) {
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
RNFetchBlob.fs.unlink(zipSourceFolder).catch(() => {
/* empty */
});
useAttachmentStore.getState().setDownloading({
groupId,
current: 0,
@@ -188,9 +190,13 @@ export async function downloadAttachments(attachmentIds: string[]) {
ToastManager.error(e as Error, "Error zipping attachments");
}
// Remove source & zip file from cache.
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
RNFetchBlob.fs.unlink(zipSourceFolder).catch(() => {
/* empty */
});
if (Platform.OS === "android") {
RNFetchBlob.fs.unlink(zipOutputFile).catch(console.log);
RNFetchBlob.fs.unlink(zipOutputFile).catch(() => {
/* empty */
});
}
}
@@ -295,8 +301,6 @@ export default async function downloadAttachment(
options?.cache ? "cache" : "file"
);
console.log("file URI", fileUri, options?.cache);
if (!options?.silent) {
ToastManager.show({
heading: strings.network.downloadSuccess(),
@@ -323,10 +327,14 @@ export default async function downloadAttachment(
if (attachment.dateUploaded) {
RNFetchBlob.fs
.unlink(RNFetchBlob.fs.dirs.CacheDir + `/${attachment.hash}`)
.catch(console.log);
.catch(() => {
/* empty */
});
RNFetchBlob.fs
.unlink(RNFetchBlob.fs.dirs.CacheDir + `/${attachment.hash}_dcache`)
.catch(console.log);
.catch(() => {
/* empty */
});
}
useAttachmentStore.getState().setDownloading({

View File

@@ -123,7 +123,9 @@ export async function downloadFile(
cancelToken.cancel = async (reason) => {
useAttachmentStore.getState().remove(filename);
request.cancel();
RNFetchBlob.fs.unlink(tempFilePath).catch(console.log);
RNFetchBlob.fs.unlink(tempFilePath).catch(() => {
/* empty */
});
DatabaseLogger.log(`Download cancelled: ${reason} ${filename}`);
};
@@ -142,7 +144,9 @@ export async function downloadFile(
useAttachmentStore.getState().remove(filename);
if (await exists(originalFilePath)) {
await RNFetchBlob.fs.unlink(originalFilePath).catch(console.log);
await RNFetchBlob.fs.unlink(originalFilePath).catch(() => {
/* empty */
});
}
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath);
@@ -169,8 +173,12 @@ export async function downloadFile(
}
useAttachmentStore.getState().remove(filename);
RNFetchBlob.fs.unlink(tempFilePath).catch(console.log);
RNFetchBlob.fs.unlink(originalFilePath).catch(console.log);
RNFetchBlob.fs.unlink(tempFilePath).catch(() => {
/* empty */
});
RNFetchBlob.fs.unlink(originalFilePath).catch(() => {
/* empty */
});
DatabaseLogger.error(e, "Download failed: ", {
url
});
@@ -188,7 +196,7 @@ export async function checkAttachment(hash: string) {
try {
const size = await getUploadedFileSize(hash);
console.log("File Size", size);
if (size === -1) return { success: true };
if (size === 0)

View File

@@ -60,7 +60,9 @@ export async function readEncrypted<TOutputFormat extends DataFormat>(
return output as Output<TOutputFormat>;
} catch (e) {
RNFetchBlob.fs.unlink(path).catch(console.log);
RNFetchBlob.fs.unlink(path).catch(() => {
/* empty */
});
DatabaseLogger.error(e);
}
}
@@ -90,8 +92,9 @@ export async function writeEncryptedBase64(
type: "url"
});
RNFetchBlob.fs.unlink(filepath).catch(console.log);
console.log("encrypted file output: ", output);
RNFetchBlob.fs.unlink(filepath).catch(() => {
/* empty */
});
return {
...output,
@@ -106,7 +109,9 @@ export async function deleteFile(
await createCacheDir();
const localFilePath = cacheDir + `/${filename}`;
if (!requestOptions) {
RNFetchBlob.fs.unlink(localFilePath).catch(console.log);
RNFetchBlob.fs.unlink(localFilePath).catch(() => {
/* empty */
});
return true;
}
@@ -117,7 +122,9 @@ export async function deleteFile(
const status = response.info().status;
const ok = status >= 200 && status < 300;
if (ok) {
RNFetchBlob.fs.unlink(localFilePath).catch(console.log);
RNFetchBlob.fs.unlink(localFilePath).catch(() => {
/* empty */
});
}
return ok;
} catch (e) {
@@ -134,10 +141,14 @@ export async function clearFileStorage() {
const oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
for (const file of files) {
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`).catch(console.log);
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`).catch(() => {
/* empty */
});
}
for (const file of oldCache) {
await RNFetchBlob.fs.unlink(cacheDirOld + `/${file}`).catch(console.log);
await RNFetchBlob.fs.unlink(cacheDirOld + `/${file}`).catch(() => {
/* empty */
});
}
} catch (e) {
DatabaseLogger.error(e, "clearFileStorage");
@@ -161,20 +172,19 @@ export async function migrateFilesFromCache() {
const migratedFilesPath = cacheDir + "/.migrated_1";
const migrated = await RNFetchBlob.fs.exists(migratedFilesPath);
if (migrated) {
console.log("Files migrated already");
return;
}
const files = await RNFetchBlob.fs.ls(cacheDir);
console.log("Files to migrate:", files.join(","));
const oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
for (const file of oldCache) {
if (file.startsWith("org.") || file.startsWith("com.")) continue;
RNFetchBlob.fs
.mv(cacheDirOld + `/${file}`, cacheDir + `/${file}`)
.catch(console.log);
console.log("Moved", file);
.catch(() => {
/* empty */
});
}
await RNFetchBlob.fs.createFile(migratedFilesPath, "1", "utf8");
} catch (e) {
@@ -183,13 +193,17 @@ export async function migrateFilesFromCache() {
}
export async function clearCache() {
await RNFetchBlob.fs.unlink(cacheDir).catch(console.log);
await RNFetchBlob.fs.unlink(cacheDir).catch(() => {
/* empty */
});
await createCacheDir();
eSendEvent("cache-cleared");
}
export async function deleteCacheFileByPath(path: string) {
await RNFetchBlob.fs.unlink(path).catch(console.log);
await RNFetchBlob.fs.unlink(path).catch(() => {
/* empty */
});
}
export async function deleteCacheFileByName(name: string) {
@@ -198,15 +212,21 @@ export async function deleteCacheFileByName(name: string) {
? await (RNFetchBlob.fs as any).pathForAppGroup(IOS_APPGROUPID)
: null;
const appGroupPath = `${iosAppGroup}/${name}`;
await RNFetchBlob.fs.unlink(appGroupPath).catch(console.log);
await RNFetchBlob.fs.unlink(`${cacheDir}/${name}`).catch(console.log);
await RNFetchBlob.fs.unlink(appGroupPath).catch(() => {
/* empty */
});
await RNFetchBlob.fs.unlink(`${cacheDir}/${name}`).catch(() => {
/* empty */
});
}
export async function deleteDCacheFiles() {
const files = await RNFetchBlob.fs.ls(cacheDir);
for (const file of files) {
if (file.includes("_dcache") || file.startsWith("NN_")) {
await RNFetchBlob.fs.unlink(file).catch(console.log);
await RNFetchBlob.fs.unlink(file).catch(() => {
/* empty */
});
}
}
}
@@ -245,7 +265,9 @@ export async function exists(filename: string) {
);
RNFetchBlob.fs
.unlink(existsInAppGroup ? appGroupPath : path)
.catch(console.log);
.catch(() => {
/* empty */
});
return false;
}
@@ -281,7 +303,7 @@ export async function getCacheSize() {
await createCacheDir();
const stat = await RNFetchBlob.fs.lstat(`file://` + cacheDir);
let total = 0;
console.log("Total files", stat.length);
stat.forEach((file) => {
total += parseInt(file.size as unknown as string);
});

View File

@@ -17,9 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function info(context: string, ...logs: unknown[]) {
console.log(`${new Date().toLocaleDateString()}::info::${context}:`, ...logs);
}
function info(context: string, ...logs: unknown[]) {}
function error(context: string, ...logs: unknown[]) {
console.log(

View File

@@ -41,7 +41,9 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
await sleep(500);
}
if (item.type === "link") {
Linking.openURL(item.data).catch(console.log);
Linking.openURL(item.data).catch(() => {
/* empty */
});
} else if (item.type === "promo") {
presentSheet({
component: (

View File

@@ -528,7 +528,9 @@ export const AttachmentDialog = ({
setAttachments(results);
setLoading(false);
})
.catch(console.log);
.catch(() => {
/* empty */
});
}}
/>
)

View File

@@ -88,7 +88,6 @@ export const ChangePassword = () => {
await sleep(300);
eSendEvent(eOpenRecoveryKeyDialog);
} catch (e) {
console.log(e.stack);
setLoading(false);
ToastManager.show({
heading: strings.passwordChangeFailed(),

View File

@@ -70,7 +70,7 @@ export const useLogin = (onFinishLogin, sessionExpired = false) => {
switch (step) {
case LoginSteps.emailAuth: {
const mfaInfo = await db.user.authenticateEmail(email.current);
console.log("email auth", mfaInfo);
if (mfaInfo) {
TwoFactorVerification.present(
async (mfa, callback) => {

View File

@@ -180,7 +180,7 @@ AttachImage.present = (response: ImageType[], context?: string) => {
close={close}
onAttach={(result) => {
resolved = true;
console.log("closing");
resolve(result);
close?.();
}}

View File

@@ -307,9 +307,7 @@ const PDFPreview = () => {
password={password}
maxScale={6}
onError={onError}
onPressLink={(uri) => {
console.log(`Link pressed: ${uri}`);
}}
onPressLink={(uri) => {}}
style={{
flex: 1,
width: width,

View File

@@ -62,7 +62,7 @@ export default function Progress() {
eSubscribeEvent(PROGRESS_EVENTS.start, (options: ProgressOptions) => {
setProgress(options.progress);
cancelCallback.current = options.cancelCallback;
console.log("options", options.fillBackground);
setData({
title: options.title,
paragraph: options.paragraph,

View File

@@ -336,7 +336,7 @@ export class VaultDialog extends Component {
);
});
}
console.log("VAULT UPDATED EVENT");
eSendEvent("vaultUpdated");
this.setState({
loading: false
@@ -406,7 +406,6 @@ export class VaultDialog extends Component {
} else {
await db.vault.add(this.state.note.id);
console.log("update note event...");
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
this.close();
@@ -543,7 +542,6 @@ export class VaultDialog extends Component {
this.close();
})
.catch((e) => {
console.log("Error", e);
this._takeErrorAction(e);
});
}

View File

@@ -78,10 +78,10 @@ class ExceptionHandler extends React.Component<{
}
export const withErrorBoundry = (Element: React.ElementType, name: string) => {
return function ErrorBoundary() {
return function ErrorBoundary(props: any) {
return (
<ExceptionHandler component={name}>
<Element />
<Element {...props} />
</ExceptionHandler>
);
};

View File

@@ -54,7 +54,7 @@ export const Header = ({
onSearch
}: {
onLeftMenuButtonPress?: () => void;
renderedInRoute: RouteName;
renderedInRoute?: RouteName;
id?: string;
title: string;
headerRightButtons?: HeaderRightButton[];

View File

@@ -41,7 +41,7 @@ export const RightMenus = ({
onSearch
}: {
headerRightButtons?: HeaderRightButton[];
renderedInRoute: RouteName;
renderedInRoute?: RouteName;
id?: string;
onPressDefaultRightButton?: () => void;
search?: boolean;

View File

@@ -41,7 +41,7 @@ export const Title = ({
isHiddenOnRender?: boolean;
accentColor?: string;
isBeta?: boolean;
renderedInRoute: string;
renderedInRoute?: string;
id?: string;
}) => {
const { colors } = useThemeColors();

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Sodium from "@ammarahmed/react-native-sodium";
import { DataURL } from "@notesnook/core";
import { DataURL, getFileNameWithExtension } from "@notesnook/core";
import type { ImageAttributes } from "@notesnook/editor";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef, useState } from "react";
@@ -86,8 +86,12 @@ const ImagePreview = () => {
return;
}
const attachment = await db.attachments.attachment(hash);
const path = `${cacheDir}/${"NN_" + attachment?.filename}`;
await RNFetchBlob.fs.mv(`${cacheDir}/${uri}`, path).catch(console.log);
const path = `${cacheDir}/${
"NN_" + (await getFileNameWithExtension(hash, attachment?.mimeType))
}`;
await RNFetchBlob.fs.mv(`${cacheDir}/${uri}`, path).catch(() => {
/* empty */
});
setImage("file://" + path);
setLoading(false);
}, 100);
@@ -95,11 +99,15 @@ const ImagePreview = () => {
const close = React.useCallback(() => {
image &&
RNFetchBlob.fs.unlink(image.replace("file://", "")).catch(console.log);
RNFetchBlob.fs.unlink(image.replace("file://", "")).catch(() => {
/* empty */
});
setImage(undefined);
setVisible(false);
}, [image]);
console.log("image", image);
const renderHeader = React.useCallback(
() => (
<View
@@ -125,13 +133,18 @@ const ImagePreview = () => {
<IconButton
name="share"
color="white"
style={{
borderWidth: 0
}}
onPress={async () => {
useSettingStore
.getState()
.setAppDidEnterBackgroundForAction(true);
await Share.open({
url: image
}).catch(console.log);
}).catch(() => {
/* empty */
});
useSettingStore
.getState()
.setAppDidEnterBackgroundForAction(false);
@@ -147,7 +160,7 @@ const ImagePreview = () => {
</View>
</View>
),
[close, image, showHeader]
[close, image, insets.top, showHeader]
);
return (

View File

@@ -153,9 +153,7 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
},
items?.cacheItem(index) ? 100 : 0
);
} catch (e) {
console.log("Error", e);
}
} catch (e) {}
})();
}, [index, items, refreshItem]);

View File

@@ -119,7 +119,6 @@ export const PricingPlans = ({
setLoading(false);
} catch (e) {
setLoading(false);
console.log("error getting sku", e);
}
}, [promo?.promoCode]);
@@ -171,7 +170,6 @@ export const PricingPlans = ({
});
return true;
} catch (e) {
console.log("PROMOCODE ERROR:", code, e);
return false;
}
};
@@ -231,7 +229,6 @@ export const PricingPlans = ({
});
} catch (e) {
setBuying(false);
console.log(e);
}
};

View File

@@ -100,7 +100,6 @@ export const AddNotebookSheet = ({
eSendEvent(eOnNotebookUpdated, parent);
if (notebook) {
setImmediate(() => {
console.log(parent, notebook.id);
eSendEvent(eOnNotebookUpdated, notebook.id);
});
}

View File

@@ -90,13 +90,12 @@ export const NotebookItem = ({
for (const key in keys) {
nextState[key] = !state.initialState[key] ? undefined : "deselected";
}
console.log("Single item selection");
state.setSelection({
[item.id]: "selected",
...nextState
});
} else {
console.log("Multi item selection");
state.markAs(item, "selected");
}
};

View File

@@ -333,13 +333,17 @@ const ExportNotesSheet = ({
if (Platform.OS === "ios") {
Share.open({
url: result?.fileDir + result.fileName
}).catch(console.log);
}).catch(() => {
/* empty */
});
} else {
FileViewer.open(result.filePath, {
showOpenWithDialog: true,
showAppsSuggestions: true,
shareFile: true
} as any).catch(console.log);
} as any).catch(() => {
/* empty */
});
}
}}
/>

View File

@@ -62,7 +62,9 @@ export const ShareComponent = ({ uri, name, padding }) => {
showOpenWithDialog: true,
showAppsSuggestions: true,
shareFile: true
}).catch(console.log);
}).catch(() => {
/* empty */
});
}}
/>
</View>

View File

@@ -113,11 +113,9 @@ const ManageTagsSheet = (props: {
.sorted()
.then((items) => {
setTags(items);
console.log("searched tags");
});
} else {
db.tags.all.sorted(db.settings.getGroupOptions("tags")).then((items) => {
console.log("items loaded tags", items.placeholders.length);
setTags(items);
});
}

View File

@@ -191,13 +191,17 @@ class RecoveryKeySheet extends React.Component {
Share.open({
url: path,
failOnCancel: false
}).catch(console.log);
}).catch(() => {
/* empty */
});
} else {
FileViewer.open(path, {
showOpenWithDialog: true,
showAppsSuggestions: true,
shareFile: true
}).catch(console.log);
}).catch(() => {
/* empty */
});
}
} catch (e) {
console.error(e);

View File

@@ -273,7 +273,7 @@ const ListNoteItem = ({
listType,
noteInternalLinks.length
]);
console.log(noteInternalLinks);
const renderBlock = React.useCallback(
(block: ContentBlock) => (
<ListBlockItem
@@ -419,7 +419,6 @@ export const ReferencesList = ({ item, close }: ReferencesListProps) => {
id={index}
items={items}
onSelect={(note, blockId) => {
console.log(note.id, blockId);
eSendEvent(eOnLoadNote, {
item: note,
blockId: blockId

View File

@@ -38,7 +38,7 @@ const Sort = ({ type, screen }) => {
);
const updateGroupOptions = async (_groupOptions) => {
const groupType = screen === "Notes" ? "home" : type + "s";
console.log("updateGroupOptions for group", groupType, "in", screen);
await db.settings.setGroupOptions(groupType, _groupOptions);
setGroupOptions(_groupOptions);
setTimeout(() => {

View File

@@ -215,7 +215,9 @@ export const Update = ({ version: appVersion, fwdRef }) => {
marginTop: 10
}}
onPress={() => {
Linking.openURL(GITHUB_PAGE_URL).catch(console.log);
Linking.openURL(GITHUB_PAGE_URL).catch(() => {
/* empty */
});
}}
>
{strings.readReleaseNotes()}

View File

@@ -315,7 +315,9 @@ const trialstarted: { id: string; steps: TStep[] } = {
actionButton: {
text: strings.joinDiscord(),
action: () => {
Linking.openURL("https://discord.gg/zQBK97EE22").catch(console.log);
Linking.openURL("https://discord.gg/zQBK97EE22").catch(() => {
/* empty */
});
}
}
}
@@ -366,7 +368,9 @@ const Support = () => {
width: "90%"
}}
onPress={() => {
Linking.openURL("https://discord.gg/zQBK97EE22").catch(console.log);
Linking.openURL("https://discord.gg/zQBK97EE22").catch(() => {
/* empty */
});
}}
icon="discord"
type="secondary"
@@ -380,7 +384,9 @@ const Support = () => {
width: "90%"
}}
onPress={() => {
Linking.openURL("https://t.me/notesnook").catch(console.log);
Linking.openURL("https://t.me/notesnook").catch(() => {
/* empty */
});
}}
icon="telegram"
type="secondary"

View File

@@ -66,6 +66,7 @@ import {
eSubscribeEvent,
presentSheet
} from "../services/event-manager";
import { IntentService } from "../services/intent";
import {
clearMessage,
setEmailVerifyMessage,
@@ -148,7 +149,6 @@ const onUploadedAttachmentProgress = (data: any) => {
};
const onUserSessionExpired = async () => {
console.log("LOGGED OUT USER....");
SettingsService.set({
sessionExpired: true
});
@@ -254,9 +254,7 @@ async function checkForShareExtensionLaunchedInBackground() {
if (note) setTimeout(() => eSendEvent("loadingNote", note), 1);
MMKV.removeItem("shareExtensionOpened");
}
} catch (e) {
console.log(e);
}
} catch (e) {}
}
async function saveEditorState() {
@@ -502,7 +500,9 @@ export const useAppEvents = () => {
}
if (SettingsService.getProperty("offlineMode")) {
db.attachments.cacheAttachments().catch(console.log);
db.attachments.cacheAttachments().catch(() => {
/* empty */
});
}
}
}, []);
@@ -550,7 +550,6 @@ export const useAppEvents = () => {
});
}
} catch (e) {
console.log(e);
ToastManager.error(e as Error, "Error updating user", "global");
}
@@ -645,6 +644,7 @@ export const useAppEvents = () => {
const emitterSubscriptions = [
Linking.addEventListener("url", onAppOpenedFromURL),
SodiumEventEmitter.addListener(
"onSodiumProgress",
onFileEncryptionProgress
@@ -695,6 +695,10 @@ export const useAppEvents = () => {
// Reset the editor if the app has been in background for more than 10 minutes.
eSendEvent(eEditorReset);
}
setTimeout(async () => {
IntentService.onAppStateChanged();
}, 100);
} else {
await saveEditorState();
if (
@@ -779,9 +783,7 @@ export const useAppEvents = () => {
useEffect(() => {
if (!appLocked && isAppLoading) {
initializeLogger()
.catch((e) => {
console.log(e);
})
.catch((e) => {})
.finally(() => {
//@ts-ignore
initializeDatabase();

View File

@@ -196,7 +196,6 @@ export const useTotalNotes = (type: "notebook" | "tag" | "color") => {
}
setTotalNotesById(totalNotesById);
});
console.log("useTotalNotes.getTotalNotes");
},
[type]
);

View File

@@ -31,7 +31,7 @@ export function useGroupOptions(type: any) {
const onUpdate = (groupType: string) => {
if (groupType !== type) return;
const options = db.settings?.getGroupOptions(type) as any;
console.log("useGroupOptions.onUpdate", type, options);
if (
groupOptions?.groupBy !== options.groupBy ||
groupOptions?.sortBy !== options.sortBy ||

View File

@@ -74,10 +74,8 @@ export const useNotebook = (
};
const onUpdate = (type: string) => {
console.log("event", type);
if (type !== "notebooks") return;
onRequestUpdate();
console.log("useNotebook.onUpdate", item?.id, Date.now());
};
eSubscribeEvent(eGroupOptionsUpdated, onUpdate);

View File

@@ -45,6 +45,9 @@ import { useSelectionStore } from "../stores/use-selection-store";
import { useSettingStore } from "../stores/use-setting-store";
import { rootNavigatorRef } from "../utils/global-refs";
import { strings } from "@notesnook/intl";
import { IntentService } from "../services/intent";
import ReminderSheet from "../components/sheets/reminder";
import { db } from "../common/database";
const NativeStack = createNativeStackNavigator();
const IntroStack = createNativeStackNavigator();
@@ -76,12 +79,24 @@ const _Tabs = () => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const height = useSettingStore((state) => state.dimensions.height);
const insets = useGlobalSafeAreaInsets();
const screenHeight = height - (50 + insets.top + insets.bottom);
React.useEffect(() => {
setTimeout(() => {
setTimeout(async () => {
useNavigationStore.getState().update(homepage);
const intent = IntentService.getLaunchIntent();
if (intent && intent["com.streetwriters.notesnook.OpenReminderId"]) {
const reminder = await db.reminders.reminder(
intent["com.streetwriters.notesnook.OpenReminderId"]
);
if (reminder) {
ReminderSheet.present(reminder);
}
} else if (intent["com.streetwriters.notesnook.NewReminder"]) {
ReminderSheet.present();
}
}, 1000);
}, [homepage]);

View File

@@ -229,7 +229,7 @@ const useLockedNoteHandler = () => {
const unlockWithBiometrics = async () => {
try {
if (!tabRef.current?.noteLocked || !tabRef.current) return;
console.log("Trying to unlock with biometrics...");
const credentials = await BiometricService.getCredentials(
"Unlock note",
"Unlock note to open it in editor."
@@ -305,7 +305,6 @@ const useLockedNoteHandler = () => {
locked: false
});
} catch (e) {
console.log(e);
ToastManager.show({
heading: strings.passwordIncorrect(),
type: "error"
@@ -324,7 +323,6 @@ const useLockedNoteHandler = () => {
unlockWithBiometrics();
}, 150);
} else {
console.log("Biometrics unavailable.", editorState().movedAway);
if (!editorState().movedAway) {
setTimeout(() => {
if (tabRef.current && tabRef.current?.locked) {

View File

@@ -74,7 +74,6 @@ export function ReadonlyEditor(props: {
}
if (editorMessage.type === EventTypes.readonlyEditorLoaded) {
console.log("Readonly editor loaded.");
props.onLoad?.((content: { data: string; id: string }) => {
setTimeout(() => {
noteId.current = content.id;
@@ -90,7 +89,6 @@ export function ReadonlyEditor(props: {
} else if (editorMessage.type === EventTypes.getAttachmentData) {
const attachment = (editorMessage.value as any).attachment as Attachment;
console.log("Getting attachment data:", attachment.hash, attachment.type);
downloadAttachment(attachment.hash, true, {
base64: attachment.type === "image",
text: attachment.type === "web-clip",
@@ -115,7 +113,6 @@ export function ReadonlyEditor(props: {
);
})
.catch(() => {
console.log("Error downloading attachment data");
editorRef.current?.postMessage(
JSON.stringify({
type: EditorEvents.attachmentData,

View File

@@ -196,9 +196,7 @@ const camera = async (options: PickerOptions) => {
options
);
})
.catch((e) => {
console.log("camera error: ", e);
});
.catch((e) => {});
} catch (e) {
ToastManager.show({
heading: (e as Error).message,
@@ -226,9 +224,7 @@ const gallery = async (options: PickerOptions) => {
options
)
)
.catch((e) => {
console.log("gallery error: ", e);
});
.catch((e) => {});
} catch (e) {
useSettingStore.getState().setAppDidEnterBackgroundForAction(false);
ToastManager.show({
@@ -236,7 +232,6 @@ const gallery = async (options: PickerOptions) => {
type: "error",
context: "global"
});
console.log("attachment error:", e);
}
};
@@ -321,18 +316,14 @@ const handleImageResponse = async (
? fileName.replace(/HEIC|HEIF/, "jpeg")
: fileName;
console.log("attaching image...", fileName);
console.log("attaching file...");
if (!(await attachFile(uri, hash, image.mime, fileName, options))) return;
if (Platform.OS === "ios") await RNFetchBlob.fs.unlink(uri);
console.log("attaching image to note...");
if (
options.tabId !== undefined &&
useTabStore.getState().getNoteIdForTab(options.tabId) === options.noteId
) {
console.log("attaching image to note...");
editorController.current?.commands.insertImage(
{
hash: hash,
@@ -407,7 +398,7 @@ export async function attachFile(
} else {
encryptionInfo = { hash: hash };
}
console.log("FILE ENCRYPTED....", encryptionInfo);
await db.attachments.add(encryptionInfo);
return true;
} catch (e) {

View File

@@ -94,4 +94,5 @@ export type AppState = {
editing: boolean;
movedAway: boolean;
timestamp: number;
noteId?: string;
};

View File

@@ -268,7 +268,6 @@ export const useEditorEvents = (
}, [editor, deviceMode, fullscreen]);
const onHardwareBackPress = useCallback(() => {
console.log(tabBarRef.current?.page());
if (tabBarRef.current?.page() === 2) {
onBackPress();
return true;
@@ -574,7 +573,7 @@ export const useEditorEvents = (
// tabs: (editorMessage.value as any)?.tabs,
// currentTab: (editorMessage.value as any)?.currentTab
// });
// console.log("Tabs updated");
//
break;
}
case EventTypes.toc:
@@ -597,14 +596,6 @@ export const useEditorEvents = (
break;
}
case EventTypes.tabFocused: {
console.log(
"Focused tab",
editorMessage.tabId,
editorMessage.noteId,
"Content:",
editorMessage.value
);
eSendEvent(eEditorTabFocused, editorMessage.tabId);
if (

View File

@@ -46,6 +46,7 @@ import {
eUnSubscribeEvent
} from "../../../services/event-manager";
import Navigation from "../../../services/navigation";
import { NotePreviewWidget } from "../../../services/note-preview-widget";
import Notifications from "../../../services/notifications";
import SettingsService from "../../../services/settings";
import { useSettingStore } from "../../../stores/use-setting-store";
@@ -152,7 +153,6 @@ export const useEditor = (
useEffect(() => {
const event = eSubscribeEvent(eEditorTabFocused, (tabId) => {
console.log("Editot tab focus changed", lastTabFocused.current, tabId);
if (lastTabFocused.current !== tabId) lock.current = false;
lastTabFocused.current = tabId as number;
});
@@ -189,7 +189,6 @@ export const useEditor = (
const reset = useCallback(
async (tabId: number, resetState = true, resetContent = true) => {
console.log("Resetting tab:", tabId);
const noteId = useTabStore.getState().getNoteIdForTab(tabId);
if (noteId) {
currentNotes.current?.id && db.fs().cancel(noteId);
@@ -392,6 +391,13 @@ export const useEditor = (
}
saveCount.current++;
clearTimeout(timers.current.onsave);
timers.current.onsave = setTimeout(async () => {
if (!id || !note) return;
NotePreviewWidget.updateNote(id, note);
}, 500);
return id;
} catch (e) {
console.error(e);
@@ -438,7 +444,6 @@ export const useEditor = (
presistTab?: boolean;
}) => {
if (!event) return;
console.log(event.item?.id, event?.item?.title, "loading note...");
if (event.blockId) {
blockIdRef.current = event.blockId;
@@ -469,7 +474,7 @@ export const useEditor = (
overlay(false);
return;
}
console.log("LOADING NOTE", event.item.id);
const item = event.item;
const currentTab = useTabStore
@@ -502,7 +507,6 @@ export const useEditor = (
}
}, 150);
}
console.log("Note already loaded, focusing the tab");
} else {
if (event.presistTab) {
// Open note in new tab.
@@ -513,9 +517,7 @@ export const useEditor = (
noteId: event.item.id,
previewTab: false
});
console.log("Opening note in new tab");
} else {
console.log("Opening note in preview tab");
// Otherwise we focus the preview tab or create one to open the note in.
useTabStore.getState().focusPreviewTab(event.item.id, {
readonly: event.item.readonly || readonly,
@@ -533,11 +535,11 @@ export const useEditor = (
const tabId = event.tabId || useTabStore.getState().currentTab;
if (lastTabFocused.current !== tabId) {
// if ((await waitForEvent(eEditorTabFocused, 1000)) !== tabId) {
// console.log("tab id did not match after focus in 1000ms");
//
// return;
// }
currentLoadingNoteId.current = item.id;
console.log("Waiting for tab to focus");
return;
}
@@ -555,7 +557,7 @@ export const useEditor = (
loadingState.current === currentContents.current[item.id]?.data
) {
// If note is already loading, return.
console.log("Note is already loading...");
return;
}
@@ -632,7 +634,6 @@ export const useEditor = (
if (isDeleted(data) || isTrashItem(data)) {
const tabId = useTabStore.getState().getTabForNote(data.id);
if (tabId !== undefined) {
console.log("Removing tab");
await commands.clearContent(tabId);
useTabStore.getState().removeTab(tabId);
}
@@ -915,6 +916,15 @@ export const useEditor = (
state.current.ready = true;
}
const appState = getAppState();
if (appState?.noteId) {
const note = await db.notes?.note(appState.noteId);
if (note) {
loadNote({
item: note
});
}
} else {
const noteId = useTabStore.getState().getCurrentNoteId();
if (!noteId) {
loadNote({ newNote: true });
@@ -933,6 +943,7 @@ export const useEditor = (
state.current.initialLoadCalled = true;
}
overlay(false);
}
}, [
postMessage,
theme,

View File

@@ -167,7 +167,7 @@ export const useTabStore = create<TabStore>(
previewTab: true,
noteId: noteId
};
console.log("focus preview", noteId);
set({
tabs: tabs
});
@@ -211,7 +211,6 @@ export const useTabStore = create<TabStore>(
focusEmptyTab: () => {
const index = get().tabs.findIndex((t) => !t.noteId);
if (index === -1) return get().newTab();
console.log("focus empty tab", get().tabs[index]);
get().focusTab(get().tabs[index].id);
},
@@ -225,7 +224,6 @@ export const useTabStore = create<TabStore>(
},
focusTab: (id: number) => {
console.log(history.getHistory(), id);
history.add(id);
set({
currentTab: id

View File

@@ -135,7 +135,6 @@ export const waitForEvent = async (
};
eSubscribeEvent(type, callback);
setTimeout(() => {
console.log("return..");
eUnSubscribeEvent(type, callback);
resolve(false);
}, waitFor);
@@ -158,6 +157,9 @@ const canRestoreAppState = (appState: AppState) => {
};
let appState: AppState | undefined;
export function setAppState(state: AppState) {
appState = state;
}
export function getAppState() {
if (appState && canRestoreAppState(appState)) return appState as AppState;
const json = NotesnookModule.getAppState();

View File

@@ -0,0 +1,169 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Note, VirtualizedGrouping } from "@notesnook/core";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { FlatList, TouchableOpacity, View } from "react-native";
import { db } from "../../common/database";
import { Header } from "../../components/header";
import Input from "../../components/ui/input";
import Paragraph from "../../components/ui/typography/paragraph";
import { useDBItem } from "../../hooks/use-db-item";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import { useSettingStore } from "../../stores/use-setting-store";
import { NotesnookModule } from "../../utils/notesnook-module";
const NoteItem = (props: {
id: string | number;
items?: VirtualizedGrouping<Note>;
}) => {
const { colors } = useThemeColors();
const [item] = useDBItem(props.id, "note", props.items);
return (
<TouchableOpacity
activeOpacity={0.7}
onPress={() => {
const widgetId = NotesnookModule.getWidgetId();
NotesnookModule.setString(
"appPreview",
String(widgetId),
JSON.stringify(item)
);
setTimeout(() => {
NotesnookModule.saveAndFinish();
});
}}
style={{
flexDirection: "column",
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
justifyContent: "center",
paddingVertical: 12,
minHeight: 45
}}
>
{!item ? null : (
<View
style={{
flexDirection: "row",
paddingHorizontal: 12
}}
>
<View
style={{
flexDirection: "column"
}}
>
<Paragraph
numberOfLines={1}
style={{
color: colors.primary.paragraph,
fontSize: 15
}}
>
{item.title}
</Paragraph>
</View>
</View>
)}
</TouchableOpacity>
);
};
export const NotePreviewConfigure = () => {
const [items, setItems] = useState<VirtualizedGrouping<Note>>();
const loading = useSettingStore((state) => state.isAppLoading);
const bounceRef = React.useRef<NodeJS.Timeout>();
const { colors } = useThemeColors();
const insets = useGlobalSafeAreaInsets();
useEffect(() => {
useSettingStore.getState().setDeviceMode("mobile");
if (loading) return;
db.notes.all.sorted(db.settings.getGroupOptions("notes")).then((notes) => {
setItems(notes);
});
}, [loading]);
const renderItem = React.useCallback(
({ index }: { item: boolean; index: number }) => {
return <NoteItem id={index} items={items} />;
},
[items]
);
return (
<View
style={{
backgroundColor: colors.primary.background,
flex: 1
}}
>
<Header
canGoBack
title="Select a note"
onLeftMenuButtonPress={() => {
NotesnookModule.cancelAndFinish();
}}
/>
<View
style={{
paddingHorizontal: 12,
paddingTop: 6
}}
>
<Input
placeholder="Search for notes"
containerStyle={{
height: 50
}}
onChangeText={(value) => {
bounceRef.current = setTimeout(() => {
if (!value) {
db.notes.all
.sorted(db.settings.getGroupOptions("notes"))
.then((notes) => {
setItems(notes);
});
return;
}
db.lookup
.notes(value)
.sorted()
.then((notes) => {
setItems(notes);
});
}, 500);
}}
/>
<FlatList
data={items?.placeholders}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="interactive"
renderItem={renderItem}
windowSize={1}
ListFooterComponent={<View style={{ height: 200 }} />}
/>
</View>
</View>
);
};

View File

@@ -284,14 +284,13 @@ NotebookScreen.navigate = async (item: Notebook, canGoBack?: boolean) => {
focusedRouteId == item?.id
) {
// Update the route in place instead
console.log("Updating existing route in place");
eSendEvent(eUpdateNotebookRoute, {
item: item,
title: item.title,
canGoBack: canGoBack
});
} else {
console.log("Pushing new notebook route");
// Push a new route
Navigation.push("Notebook", {
title: item.title,

View File

@@ -59,7 +59,6 @@ ColoredNotes.navigate = (item: Color, canGoBack: boolean) => {
const { focusedRouteId } = useNavigationStore.getState();
if (focusedRouteId === item.id) {
console.log("ColoredNotes.navigate: route already focused for color");
return;
}

View File

@@ -171,7 +171,6 @@ const NotesPage = ({
setLoadingNotes(false);
})
.catch((e) => {
console.log("Error loading notes", params.current?.title, e, e.stack);
setLoadingNotes(false);
});
}

View File

@@ -60,7 +60,6 @@ TaggedNotes.navigate = (item: Tag, canGoBack?: boolean) => {
const { focusedRouteId } = useNavigationStore.getState();
if (focusedRouteId === item.id) {
console.log("TaggedNotes.navigate: route already focused for tag");
return;
}

View File

@@ -160,9 +160,7 @@ export default function DebugLogs() {
type: "success"
});
}
} catch (e) {
console.log(e);
}
} catch (e) {}
}, [currentLog?.logs]);
const copyLogs = React.useCallback(() => {

View File

@@ -54,7 +54,9 @@ export const Licenses = () => {
}}
onPress={() => {
if (!item.link) return;
Linking.openURL(item.link).catch(console.log);
Linking.openURL(item.link).catch(() => {
/* empty */
});
}}
>
<Heading size={SIZE.sm}>{item.name}</Heading>

View File

@@ -33,7 +33,6 @@ import { strings } from "@notesnook/intl";
export const FontPicker = createSettingsPicker({
getValue: () => useSettingStore.getState().settings.defaultFontFamily,
updateValue: (item) => {
console.log(item.id);
SettingsService.set({
defaultFontFamily: item.id
});

View File

@@ -197,7 +197,6 @@ const restoreBackup = async (options: {
const attachment = await db.attachments.attachment(hash as string);
if (!attachment) continue;
console.log("Saving attachment file", hash);
await deleteCacheFileByName(hash);
await RNFetchBlob.fs.cp(
`${zipOutputFolder}/attachments/${hash}`,
@@ -208,9 +207,13 @@ const restoreBackup = async (options: {
progress: strings.cleaningUp()
});
// Remove files from cache
RNFetchBlob.fs.unlink(zipOutputFolder).catch(console.log);
RNFetchBlob.fs.unlink(zipOutputFolder).catch(() => {
/* empty */
});
if (Platform.OS === "android" || deleteBackupFile) {
RNFetchBlob.fs.unlink(filePath).catch(console.log);
RNFetchBlob.fs.unlink(filePath).catch(() => {
/* empty */
});
}
} else {
updateProgress({

View File

@@ -389,7 +389,12 @@ export const settingsGroups: SettingSection[] = [
useHook: () => {
const [cacheSize, setCacheSize] = React.useState(0);
React.useEffect(() => {
filesystem.getCacheSize().then(setCacheSize).catch(console.log);
filesystem
.getCacheSize()
.then(setCacheSize)
.catch(() => {
/* empty */
});
const sub = eSubscribeEvent("cache-cleared", () => {
setCacheSize(0);
});
@@ -532,7 +537,7 @@ export const settingsGroups: SettingSection[] = [
endProgress();
} catch (e) {
endProgress();
console.log(e);
ToastManager.error(
e as Error,
strings.failedToDeleteAccount(),
@@ -568,7 +573,9 @@ export const settingsGroups: SettingSection[] = [
}
PremiumService.verify(() => {
SettingsService.setProperty("offlineMode", true);
db.attachments.cacheAttachments().catch(console.log);
db.attachments.cacheAttachments().catch(() => {
/* empty */
});
});
}
},
@@ -1459,7 +1466,9 @@ export const settingsGroups: SettingSection[] = [
name: strings.joinTelegram(),
description: strings.joinTelegramDesc(),
modifer: () => {
Linking.openURL("https://t.me/notesnook").catch(console.log);
Linking.openURL("https://t.me/notesnook").catch(() => {
/* empty */
});
}
},
{
@@ -1479,7 +1488,9 @@ export const settingsGroups: SettingSection[] = [
description: strings.followOnXDesc(),
icon: "twitter",
modifer: () => {
Linking.openURL("https://twitter.com/notesnook").catch(console.log);
Linking.openURL("https://twitter.com/notesnook").catch(() => {
/* empty */
});
}
},
{
@@ -1487,7 +1498,9 @@ export const settingsGroups: SettingSection[] = [
name: strings.joinDiscord(),
icon: "discord",
modifer: async () => {
Linking.openURL("https://discord.gg/zQBK97EE22").catch(console.log);
Linking.openURL("https://discord.gg/zQBK97EE22").catch(() => {
/* empty */
});
},
description: strings.joinDiscordDesc()
}

View File

@@ -25,6 +25,7 @@ import {
import { DatabaseLogger, db, setupDatabase } from "../common/database";
import { deleteDCacheFiles } from "../common/filesystem/io";
import { useUserStore } from "../stores/use-user-store";
import { NotePreviewWidget } from "./note-preview-widget";
import Notifications from "./notifications";
import SettingsService from "./settings";
@@ -85,7 +86,6 @@ const task = async (event: { taskId: string; timeout: boolean }) => {
const taskId = event.taskId;
const isTimeout = event.timeout; // <-- true when your background-time has expired.
if (isTimeout) {
console.log(`BACKGROUND FETCH TIMEOUT: ${taskId}`);
BackgroundFetch.finish(taskId);
return;
}
@@ -112,12 +112,13 @@ async function onBackgroundSyncStarted() {
useUserStore.getState().setSyncing(false);
}
await Notifications.setupReminders();
NotePreviewWidget.updateNotes();
deleteDCacheFiles();
DatabaseLogger.info("BACKGROUND SYNC COMPLETE");
} catch (e) {
useUserStore.getState().setSyncing(false);
DatabaseLogger.error(e as Error);
console.log("BACKGROUND SYNC ERROR", (e as Error).message);
}
}
@@ -142,7 +143,6 @@ const onBoot = async () => {
DatabaseLogger.info("BOOT TASK COMPLETE");
} catch (e) {
DatabaseLogger.error(e as Error);
console.log(e);
}
};

View File

@@ -120,13 +120,17 @@ async function presentBackupCompleteSheet(backupFilePath: string) {
Share.open({
url: backupFilePath,
failOnCancel: false
}).catch(console.log);
}).catch(() => {
/* empty */
});
} else {
FileViewer.open(backupFilePath, {
showOpenWithDialog: true,
showAppsSuggestions: true,
shareFile: true
} as any).catch(console.log);
} as any).catch(() => {
/* empty */
});
}
},
actionText: strings.share()
@@ -161,8 +165,6 @@ async function run(
context?: string,
backupType: "full" | "partial" = "partial"
) {
console.log("Creating backup:", backupType, progress, context);
const androidBackupDirectory = (await checkBackupDirExists(
false,
context
@@ -203,7 +205,9 @@ async function run(
? `${path}/${backupFileName}.nnbackupz`
: `${cacheDir}/${backupFileName}.nnbackupz`;
await RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
await RNFetchBlob.fs.unlink(zipSourceFolder).catch(() => {
/* empty */
});
await RNFetchBlob.fs.mkdir(zipSourceFolder);
const attachmentsDir = zipSourceFolder + "/attachments";
@@ -253,18 +257,21 @@ async function run(
`${backupFileName}.nnbackupz`,
"application/nnbackupz"
);
console.log("Copying zip file...");
await copyFileAsync(`file://${zipOutputFile}`, file.uri);
console.log("Copied zip file...");
path = file.uri;
} else {
path = zipOutputFile;
}
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
RNFetchBlob.fs.unlink(zipSourceFolder).catch(() => {
/* empty */
});
if (Platform.OS === "android") {
RNFetchBlob.fs.unlink(zipOutputFile).catch(console.log);
RNFetchBlob.fs.unlink(zipOutputFile).catch(() => {
/* empty */
});
}
updateNextBackupTime(backupType || "partial");
@@ -308,9 +315,13 @@ async function run(
return run(progress, context, backupType);
}
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
RNFetchBlob.fs.unlink(zipSourceFolder).catch(() => {
/* empty */
});
if (Platform.OS === "android") {
RNFetchBlob.fs.unlink(zipOutputFile).catch(console.log);
RNFetchBlob.fs.unlink(zipOutputFile).catch(() => {
/* empty */
});
}
DatabaseLogger.error(e);
@@ -329,7 +340,6 @@ async function checkBackupRequired(
type: "daily" | "off" | "useroff" | "weekly" | "monthly" | "never",
lastBackupDateType: "lastBackupDate" | "lastFullBackupDate" = "lastBackupDate"
) {
console.log(lastBackupDateType, type);
if (type === "off" || type === "useroff" || type === "never" || !type) return;
const now = Date.now();
const lastBackupDate = SettingsService.getProperty(lastBackupDateType) as
@@ -362,9 +372,7 @@ const checkAndRun = async () => {
if (await checkBackupRequired(settings?.reminder)) {
try {
await run();
} catch (e) {
console.log(e);
}
} catch (e) {}
}
};

View File

@@ -123,7 +123,6 @@ export type PresentSheetOptions = {
};
export function presentSheet(data: Partial<PresentSheetOptions>) {
console.log("PRESENTING...");
eSendEvent(eOpenSheet, data);
}

View File

@@ -85,7 +85,7 @@ async function resolveFileFunctions(
`/export_${Date.now()}`
);
await RNFetchBlob.fs.mkdir(exportCacheFolder).catch((e) => console.log(e));
await RNFetchBlob.fs.mkdir(exportCacheFolder).catch((e) => {});
const mkdir = async (dir: string) => {
const folder = join(exportCacheFolder, dir);
@@ -96,7 +96,7 @@ async function resolveFileFunctions(
const writeFile = async (path: string, result: string) => {
const cacheFilePath = join(exportCacheFolder, path);
console.log(cacheFilePath, result.length);
await RNFetchBlob.fs.writeFile(
cacheFilePath,
result,
@@ -194,7 +194,7 @@ async function bulkExport(
try {
await exportNoteToFile(item, type, mkdir, writeFile);
} catch (e) {
console.log(item.type, e);
/* empty */
}
} else if (item.type === "attachment") {
currentAttachmentProgress += 1;
@@ -202,11 +202,11 @@ async function bulkExport(
try {
await exportAttachmentToFile(item, mkdir, cacheFolder);
} catch (e) {
console.log(item.path, e);
/* empty */
}
}
}
console.log(cacheFolder);
return createZip(totalNotes, cacheFolder, type, path, callback);
}
@@ -240,7 +240,7 @@ async function exportNote(
noteItem = item;
await exportNoteToFile(item, type, mkdir, writeFile);
} catch (e) {
console.log("exportNoteToFile", item.type, e);
/* empty */
}
} else if (item.type === "attachment") {
currentAttachmentProgress += 1;
@@ -249,13 +249,12 @@ async function exportNote(
hasAttachments = true;
await exportAttachmentToFile(item, mkdir, cacheFolder);
} catch (e) {
console.log("exportAttachmentToFile", item.path, e);
/* empty */
}
}
}
if (!hasAttachments) {
console.log("creating file...");
return createFile(noteItem as ExportableNote, type, path, cacheFolder);
} else {
return createZip(1, cacheFolder, type, path, callback);
@@ -333,10 +332,10 @@ async function createFile(
filePath = originalPath.replace(`${ext}`, "") + "_" + id + ext;
id++;
}
console.log("path", filePath);
await RNFetchBlob.fs.mv(exportedFile, filePath);
}
console.log("file moved...");
return {
filePath: filePath,
fileDir: path,

View File

@@ -0,0 +1,73 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Platform } from "react-native";
import { db } from "../common/database";
import ReminderSheet from "../components/sheets/reminder";
import { setAppState } from "../screens/editor/tiptap/utils";
import { eOnLoadNote } from "../utils/events";
import { tabBarRef } from "../utils/global-refs";
import { NotesnookModule } from "../utils/notesnook-module";
import { eSendEvent } from "./event-manager";
const launchIntent = Platform.OS === "ios" ? {} : NotesnookModule.getIntent();
let used = false;
let launched = false;
export const IntentService = {
getLaunchIntent() {
if (used || Platform.OS === "ios") return null;
used = true;
return launchIntent;
},
onLaunch() {
if (launched || Platform.OS === "ios") return;
launched = true;
if (launchIntent["com.streetwriters.notesnook.OpenNoteId"]) {
setAppState({
movedAway: false,
editing: true,
timestamp: Date.now(),
noteId: launchIntent["com.streetwriters.notesnook.OpenNoteId"]
});
}
},
async onAppStateChanged() {
if (Platform.OS === "ios") return;
const intent = NotesnookModule.getIntent();
if (intent["com.streetwriters.notesnook.OpenNoteId"]) {
const note = await db.notes.note(
intent["com.streetwriters.notesnook.OpenNoteId"]
);
if (note) {
eSendEvent(eOnLoadNote, {
item: note
});
tabBarRef.current?.goToPage(1, false);
}
} else if (intent["com.streetwriters.notesnook.OpenReminderId"]) {
const reminder = await db.reminders.reminder(
intent["com.streetwriters.notesnook.OpenReminderId"]
);
if (reminder) ReminderSheet.present(reminder);
} else if (intent["com.streetwriters.notesnook.NewReminder"]) {
ReminderSheet.present();
}
}
};

View File

@@ -122,7 +122,6 @@ function queueRoutesForUpdate(...routesToUpdate: RouteName[]) {
}
function navigate<T extends RouteName>(screen: T, params?: RouteParams[T]) {
console.log(`Navigation.navigate ${screen} route`);
rootNavigatorRef.current?.navigate(screen as any, params);
}
@@ -131,17 +130,14 @@ function goBack() {
}
function push<T extends RouteName>(screen: T, params: RouteParams[T]) {
console.log(`Navigation.push ${screen} route`);
rootNavigatorRef.current?.dispatch(StackActions.push(screen as any, params));
}
function replace<T extends RouteName>(screen: T, params: RouteParams[T]) {
console.log(`Navigation.replace ${screen} route`);
rootNavigatorRef.current?.dispatch(StackActions.replace(screen, params));
}
function popToTop() {
console.log(`Navigation.popToTop`);
rootNavigatorRef.current?.dispatch(StackActions.popToTop());
}

View File

@@ -0,0 +1,45 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Note } from "@notesnook/core";
import { db } from "../common/database";
import { NotesnookModule } from "../utils/notesnook-module";
import { Platform } from "react-native";
let timer: NodeJS.Timeout;
export const NotePreviewWidget = {
updateNotes: () => {
if (Platform.OS !== "android") return;
clearTimeout(timer);
timer = setTimeout(async () => {
const noteIds = await NotesnookModule.getWidgetNotes();
for (const id of noteIds) {
const newNote = await db.notes.note(id);
if (!newNote) continue;
NotesnookModule.updateWidgetNote(id, JSON.stringify(newNote));
}
}, 500);
},
updateNote: async (id: string, note: Note) => {
if (Platform.OS !== "android") return;
if (id && (await NotesnookModule.hasWidgetNote(id))) {
NotesnookModule.updateWidgetNote(id, JSON.stringify(note));
}
}
};

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Reminder } from "@notesnook/core";
import { isReminderActive, Reminder } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import notifee, {
AndroidStyle,
@@ -51,6 +51,7 @@ import { DDS } from "./device-detection";
import { eSendEvent } from "./event-manager";
import Navigation from "./navigation";
import SettingsService from "./settings";
import { getFormattedReminderTime } from "@notesnook/common";
let pinned: DisplayedNotification[] = [];
@@ -120,7 +121,7 @@ const onEvent = async ({ type, detail }: Event) => {
await scheduleNotification(reminder);
}
}
updateRemindersForWidget();
return;
}
if (type === EventType.PRESS) {
@@ -141,7 +142,7 @@ const onEvent = async ({ type, detail }: Event) => {
}
editorState().movedAway = false;
const noteId = notification?.id;
console.log("NOTE ID", noteId);
loadNote(noteId as string, true);
}
@@ -167,6 +168,7 @@ const onEvent = async ({ type, detail }: Event) => {
);
useRelationStore.getState().update();
useReminderStore.getState().refresh();
updateRemindersForWidget();
break;
}
case "REMINDER_DISABLE": {
@@ -184,6 +186,7 @@ const onEvent = async ({ type, detail }: Event) => {
);
useRelationStore.getState().update();
useReminderStore.getState().refresh();
updateRemindersForWidget();
break;
}
case strings.unpin(): {
@@ -235,11 +238,9 @@ const onEvent = async ({ type, detail }: Event) => {
try {
if (!globalThis["IS_MAIN_APP_RUNNING" as never]) {
await db.sync({ type: "send", force: false });
} else {
console.log("main app running, skipping sync");
}
} catch (e) {
console.log(e, (e as Error).stack);
/* empty */
}
}
Navigation.queueRoutesForUpdate();
@@ -249,6 +250,35 @@ const onEvent = async ({ type, detail }: Event) => {
}
};
type ReminderWithFormattedTime = Reminder & {
formattedTime?: string;
};
async function updateRemindersForWidget() {
if (Platform.OS === "ios") return;
const reminders: ReminderWithFormattedTime[] = await db.reminders?.all.items(
undefined,
{
sortBy: "dueDate",
sortDirection: "desc"
}
);
const activeReminders = [];
if (!reminders) return;
for (const reminder of reminders) {
if (isReminderActive(reminder)) {
reminder.formattedTime = getFormattedReminderTime(reminder);
activeReminders.push(reminder);
}
}
NotesnookModule.setString(
"appPreview",
"remindersList",
JSON.stringify(activeReminders)
);
NotesnookModule.updateReminderWidget();
}
async function setupIOSCategories() {
try {
if (Platform.OS === "ios") {
@@ -288,7 +318,7 @@ async function setupIOSCategories() {
}
}
} catch (e) {
console.log("ERROR in setupIOSCategories", e);
/* empty */
}
}
@@ -398,8 +428,9 @@ async function scheduleNotification(
trigger
);
}
updateRemindersForWidget();
} catch (e) {
console.log("Schedule notification", e);
/* empty */
}
}
@@ -542,7 +573,7 @@ async function displayNotification({
}
});
} catch (e) {
console.log(e);
/* empty */
}
}
@@ -943,6 +974,7 @@ async function setupReminders(checkNeedsScheduling = false) {
trigger.notification.id &&
notifee.cancelTriggerNotification(trigger.notification.id as string)
);
updateRemindersForWidget();
}
async function pinNote(id: string) {
@@ -963,7 +995,7 @@ async function pinNote(id: string) {
id: note.id
});
} catch (e) {
console.log(e);
/* empty */
}
}
const Events = {
@@ -988,7 +1020,8 @@ const Notifications = {
getChannelId,
isNotePinned,
pinNote,
Events
Events,
updateRemindersForWidget
};
export default Notifications;

View File

@@ -76,9 +76,7 @@ async function setPremiumStatus() {
products = await RNIap.getSubscriptions({
skus: itemSkus
});
} catch (e) {
console.log("subscriptions: ", e);
}
} catch (e) {}
if (premiumStatus === 0 && !__DEV__) {
SettingsService.reset();
}
@@ -299,7 +297,6 @@ const subscriptions = {
}
};
console.log("Subscription.verify", requestData);
try {
let result = await fetch(
__DEV__
@@ -307,7 +304,7 @@ const subscriptions = {
: "https://payments.streetwriters.co/apple/verify",
requestData
);
console.log("Subscribed", result);
let text = await result.text();
if (!result.ok) {
@@ -318,9 +315,7 @@ const subscriptions = {
} else {
await subscriptions.clear(subscription);
}
} catch (e) {
console.log("subscription error", e);
}
} catch (e) {}
}
}
},

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { db } from "../common/database";
import Navigation from "../services/navigation";
import { NotePreviewWidget } from "../services/note-preview-widget";
import Notifications from "../services/notifications";
import { useFavoriteStore } from "./use-favorite-store";
import { useMenuStore } from "./use-menu-store";
@@ -41,6 +42,8 @@ export function initAfterSync() {
useUserStore.setState({
profile: db.settings.getProfile()
});
NotePreviewWidget.updateNotes();
}
export async function initialize() {}

View File

@@ -80,7 +80,6 @@ export const useMenuStore = create<MenuStore>((set, get) => ({
JSON.stringify(get().hiddenItems || {}) !==
JSON.stringify(hiddenItems || {})
) {
console.log(order, hiddenItems);
set({
order: order,
hiddenItems: hiddenItems

View File

@@ -126,7 +126,6 @@ export const useMessageStore = create<MessageStore>((set, get) => ({
announcements = [];
}
} catch (e) {
console.log(e);
set({ announcements: [] });
} finally {
const all = await getFiltered(announcements);

View File

@@ -106,7 +106,6 @@ const useNavigationStore = create<NavigationStore>((set, get) => ({
set({
focusedRouteId: id
});
console.log("CurrentRoute ID", id);
},
currentRoute: "Notes",
canGoBack: false,
@@ -114,7 +113,6 @@ const useNavigationStore = create<NavigationStore>((set, get) => ({
set({
currentRoute: currentScreen
});
console.log("CurrentRoute", currentScreen);
},
headerRightButtons: [],
buttonAction: () => null,

View File

@@ -49,7 +49,7 @@ export async function attachFile(uri, hash, type, filename, options) {
encryptionInfo.filename = filename;
encryptionInfo.alg = "xcha-stream";
encryptionInfo.key = key;
console.log(encryptionInfo);
if (options?.reupload && exists) await db.attachments.reset(hash);
} else {
encryptionInfo = { hash: hash };
@@ -57,9 +57,12 @@ export async function attachFile(uri, hash, type, filename, options) {
await db.attachments.add(encryptionInfo, options?.id);
return true;
} catch (e) {
if (Platform.OS === "ios") RNFetchBlob.fs.unlink(uri).catch(console.log);
if (Platform.OS === "ios")
RNFetchBlob.fs.unlink(uri).catch(() => {
/* empty */
});
DatabaseLogger.error(e, "Attach file error");
console.log("attach file error: ", e);
return false;
}
}
@@ -102,12 +105,10 @@ async function createNotes(bundle) {
const isJpeg = /(jpeg|jpg)/g.test(file.type);
if ((isPng || isJpeg) && compress) {
console.log(uri, "before compressed");
uri = await compressToFile("file://" + uri, isPng ? "PNG" : "JPEG");
uri = `${uri.replace("file://", "")}`;
}
console.log(uri, "after compressed");
const hash = await Sodium.hashFile({
uri: uri,

View File

@@ -25,6 +25,21 @@ interface NotesnookModuleInterface {
setSecureMode: (enabled: boolean) => void;
setAppState: (appState: string) => void;
getAppState: () => string;
saveAndFinish: () => void;
setString: (storeName: string, key: string, value: string) => void;
getString: (storeName: string, key: string) => Promise<string>;
removeString: (key: string) => void;
cancelAndFinish: () => void;
getWidgetId: () => void;
getIntent: () => {
"com.streetwriters.notesnook.OpenNoteId"?: string;
"com.streetwriters.notesnook.OpenReminderId"?: string;
"com.streetwriters.notesnook.NewReminder"?: string;
};
getWidgetNotes: () => Promise<string[]>;
hasWidgetNote: (noteId: string) => Promise<boolean>;
updateWidgetNote: (noteId: string, data: string) => void;
updateReminderWidget: () => void;
}
export const NotesnookModule: NotesnookModuleInterface = Platform.select({
@@ -33,7 +48,18 @@ export const NotesnookModule: NotesnookModuleInterface = Platform.select({
setBackgroundColor: () => {},
setSecureMode: () => {},
setAppState: () => {},
getAppState: () => {}
getAppState: () => {},
saveAndFinish: () => {},
getString: () => {},
setString: () => {},
removeString: () => {},
cancelAndFinish: () => {},
getWidgetId: () => {},
getIntent: () => {},
getWidgetNotes: () => {},
hasWidgetNote: () => {},
updateWidgetNote: () => {},
updateReminderWidget: () => {}
},
android: NativeModules.NNativeModule
});

View File

@@ -212,6 +212,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.2'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.9.2'
implementation 'com.google.code.gson:gson:2.11.0'
androidTestImplementation('com.wix:detox:+')
implementation 'androidx.appcompat:appcompat:1.1.0'

View File

@@ -60,10 +60,18 @@
android:theme="@style/BootTheme"
android:largeHeap="true"
android:supportsRtl="false"
android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:supportsRtl">
<receiver android:exported="false" android:name=".NoteWidget">
<receiver android:exported="false" android:label="@string/reminders_title" android:name=".ReminderWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_reminders_info" />
</receiver>
<receiver android:exported="false" android:label="@string/quick_note" android:name=".NoteWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -73,6 +81,27 @@
android:resource="@xml/new_note_widget_info" />
</receiver>
<receiver android:exported="false" android:label="@string/note" android:name=".NotePreviewWidget">
<intent-filter>"
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/note_widget_info" />
</receiver>
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:label="NotePreviewConfigure"
android:launchMode="singleTask"
android:exported="true"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize" android:name=".NotePreviewConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
@@ -166,6 +195,11 @@
</intent-filter>
</service>
<service
android:name=".ReminderViewsService"
android:exported="true"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
@@ -193,9 +227,6 @@
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -3,7 +3,6 @@ package com.streetwriters.notesnook;
import com.facebook.react.ReactActivity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebView;
import com.facebook.react.ReactActivityDelegate;
@@ -12,22 +11,17 @@ import com.facebook.react.defaults.DefaultReactActivityDelegate;
import com.zoontek.rnbootsplash.RNBootSplash;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
RNBootSplash.init(this);
super.onCreate(null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG) {
if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true);
}
try {
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
} catch (Exception e) {
}
} catch (Exception ignored) {}
}
/**
@@ -63,7 +57,6 @@ public void onConfigurationChanged(Configuration newConfig) {
return "Notesnook";
}
@Override
public void invokeDefaultOnBackPressed() {
moveTaskToBack(true);

View File

@@ -22,6 +22,7 @@ class MainApplication : Application(), ReactApplication {
add(NNativeModulePackage());
}
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

View File

@@ -0,0 +1,71 @@
package com.streetwriters.notesnook;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import com.google.gson.Gson;
import com.streetwriters.notesnook.datatypes.Note;
public class NotePreviewConfigureActivity extends ReactActivity {
static int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
static NotePreviewConfigureActivity activity;
/**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
* (aka React 18) with two boolean flags.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
NotePreviewConfigureActivity.appWidgetId = appWidgetId;
}
Intent resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(Activity.RESULT_CANCELED, resultValue);
activity = this;
}
public static void saveAndFinish(Context context) {
if (NotePreviewConfigureActivity.activity == null || appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) return;
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
NotePreviewWidget.updateAppWidget(context, appWidgetManager, appWidgetId);
Intent resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
NotePreviewConfigureActivity.activity.setResult(RESULT_OK, resultValue);
NotePreviewConfigureActivity.activity.finish();
}
@Override
protected String getMainComponentName() {
return "NotePreviewConfigure";
}
}

View File

@@ -0,0 +1,63 @@
package com.streetwriters.notesnook;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.widget.RemoteViews;
import com.google.gson.Gson;
import com.streetwriters.notesnook.datatypes.Note;
public class NotePreviewWidget extends AppWidgetProvider {
static String OpenNoteId = "com.streetwriters.notesnook.OpenNoteId";
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
String data = context.getSharedPreferences("appPreview", Context.MODE_PRIVATE).getString(String.valueOf(appWidgetId), "");
if (data.isEmpty()) {
return;
}
Gson gson = new Gson();
Note note = gson.fromJson(data, Note.class);
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(OpenNoteId, note.getId());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, getActivityOptionsBundle());
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.note_widget);
views.setTextViewText(R.id.widget_title, note.getTitle());
views.setTextViewText(R.id.widget_body, note.getHeadline());
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
private static Bundle getActivityOptionsBundle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
ActivityOptions activityOptions = ActivityOptions.makeBasic();
activityOptions.setPendingIntentBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
return activityOptions.toBundle();
} else
return null;
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
SharedPreferences.Editor edit = context.getSharedPreferences("appPreview", Context.MODE_PRIVATE).edit();
for (int id: appWidgetIds) {
edit.remove(String.valueOf(id));
}
edit.apply();
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
}

View File

@@ -1,10 +1,12 @@
package com.streetwriters.notesnook;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.widget.RemoteViews;
@@ -15,16 +17,26 @@ public class NoteWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
Intent intent = new Intent(context, ShareActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.note_widget);
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_note_widget);
setClickIntent(context, views);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
static void setClickIntent(Context context, RemoteViews views) {
Intent intent = new Intent(context, ShareActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, getActivityOptionsBundle());
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
}
private static Bundle getActivityOptionsBundle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
ActivityOptions activityOptions = ActivityOptions.makeBasic();
activityOptions.setPendingIntentBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
return activityOptions.toBundle();
} else
return null;
}
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
@@ -33,21 +45,20 @@ public class NoteWidget extends AppWidgetProvider {
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle options) {
int minWidth = options != null ? options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) : 0;
// int minHeight = options != null ? options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) : 0;
int minHeight = options != null ? options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) : 0;
int layoutId = (minWidth < 100) ? R.layout.note_widget_icon : R.layout.note_widget;
int layoutId = (minWidth < 100) ? R.layout.new_note_widget_icon : R.layout.new_note_widget;
RemoteViews views = new RemoteViews(context.getPackageName(), layoutId);
setClickIntent(context, views);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
updateAppWidget(context, appWidgetManager, appWidgetId,null);
}
}
}

View File

@@ -1,21 +1,35 @@
package com.streetwriters.notesnook;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.RemoteViews;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.gson.Gson;
import com.streetwriters.notesnook.datatypes.Note;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RCTNNativeModule extends ReactContextBaseJavaModule {
Intent lastIntent;
ReactContext mContext;
public RCTNNativeModule(ReactApplicationContext reactContext) {
@@ -31,7 +45,6 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
@ReactMethod
public void setBackgroundColor(final String color) {
try {
getCurrentActivity().getWindow().getDecorView().setBackgroundColor(Color.parseColor(color));
} catch (Exception e) {
@@ -48,8 +61,6 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
}
}
@ReactMethod
public void setSecureMode(final boolean mode) {
try {
@@ -85,6 +96,118 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
return appStateValue.isEmpty() ? null : appStateValue;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public int getWidgetId() {
return NotePreviewConfigureActivity.appWidgetId;
}
@ReactMethod
public void setString(final String storeName, final String key, final String value) {
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = details.edit();
edit.putString(key, value);
edit.apply();
}
@ReactMethod
public void removeString(final String storeName, final String key) {
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = details.edit();
edit.remove(key);
edit.apply();
}
@ReactMethod
public void getString(final String storeName, final String key, Promise promise) {
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
String value = details.getString(key, "");
promise.resolve(value.isEmpty() ? null : value);
}
@ReactMethod
public void saveAndFinish() {
NotePreviewConfigureActivity.saveAndFinish(mContext);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getIntent() {
WritableMap map = Arguments.createMap();
if (getCurrentActivity() != null) {
Intent intent = getCurrentActivity().getIntent();
Bundle extras = getCurrentActivity().getIntent().getExtras();
if (extras != null && intent != lastIntent) {
lastIntent = intent;
map.putString(NotePreviewWidget.OpenNoteId, extras.getString(NotePreviewWidget.OpenNoteId));
map.putString(ReminderViewsService.OpenReminderId, extras.getString(ReminderViewsService.OpenReminderId));
map.putString(ReminderWidgetProvider.NewReminder, extras.getString(ReminderWidgetProvider.NewReminder));
}
}
return map;
}
@ReactMethod
public void cancelAndFinish() {
NotePreviewConfigureActivity.activity.setResult(Activity.RESULT_CANCELED);
NotePreviewConfigureActivity.activity.finish();
}
@ReactMethod
public void getWidgetNotes(Promise promise) {
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
Map<String, ?> map = pref.getAll();
WritableArray arr = Arguments.createArray();
for(Map.Entry<String,?> entry : map.entrySet()){
if (entry.getKey().equals("remindersList")) continue;
String value = (String) entry.getValue();
Gson gson = new Gson();
Note note = gson.fromJson(value, Note.class);
arr.pushString(note.getId());
}
promise.resolve(arr);
}
@ReactMethod
public void hasWidgetNote(final String noteId, Promise promise) {
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
Map<String, ?> map = pref.getAll();
boolean found = false;
for(Map.Entry<String,?> entry : map.entrySet()){
String value = (String) entry.getValue();
if (value.contains(noteId)) {
found = true;
}
}
promise.resolve(found);
}
@ReactMethod
public void updateWidgetNote(final String noteId, final String data) {
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
Map<String, ?> map = pref.getAll();
SharedPreferences.Editor edit = pref.edit();
ArrayList<String> ids = new ArrayList<>();
for(Map.Entry<String,?> entry : map.entrySet()) {
String value = (String) entry.getValue();
if (value.contains(noteId)) {
edit.putString(entry.getKey(), data);
ids.add(entry.getKey());
}
}
edit.apply();
for (String id: ids) {
NotePreviewWidget.updateAppWidget(mContext, AppWidgetManager.getInstance(mContext), Integer.parseInt(id));
}
}
@ReactMethod
public void updateReminderWidget() {
AppWidgetManager wm = AppWidgetManager.getInstance(mContext);
int[] ids = wm.getAppWidgetIds(ComponentName.createRelative(mContext.getPackageName(), ReminderWidgetProvider.class.getName()));
for (int id: ids) {
Log.d("Reminders", "Updating" + id);
RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget_reminders);
ReminderWidgetProvider.updateAppWidget(mContext, wm, id, views);
wm.notifyAppWidgetViewDataChanged(id, R.id.widget_list_view);
}
}
}

View File

@@ -0,0 +1,100 @@
package com.streetwriters.notesnook;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViewsService;
import android.content.Context;
import android.widget.RemoteViews;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.streetwriters.notesnook.datatypes.Reminder;
import java.util.ArrayList;
import java.util.List;
public class ReminderViewsService extends RemoteViewsService {
static String OpenReminderId = "com.streetwriters.notesnook.OpenReminderId";
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new ReminderRemoteViewsFactory(this.getApplicationContext(), intent);
}
}
class ReminderRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context context;
private List<Reminder> reminders;
public ReminderRemoteViewsFactory(Context context, Intent intent) {
this.context = context;
}
@Override
public void onCreate() {
// Initialize reminders list
reminders = new ArrayList<Reminder>();
}
@Override
public void onDataSetChanged() {
reminders.clear();
SharedPreferences preferences = context.getSharedPreferences("appPreview", Context.MODE_PRIVATE);
Gson gson = new Gson();
reminders = gson.fromJson(preferences.getString("remindersList","[]"), new TypeToken<List<Reminder>>(){}.getType());
}
@Override
public void onDestroy() {
reminders.clear();
}
@Override
public int getCount() {
return reminders.size();
}
@Override
public RemoteViews getViewAt(int position) {
Reminder reminder = reminders.get(position);
boolean useMiniLayout = reminder.getDescription() == null || reminder.getDescription().isEmpty();
RemoteViews views = new RemoteViews(context.getPackageName(), useMiniLayout ? R.layout.widget_reminder_layout_small : R.layout.widget_reminder_layout);
views.setTextViewText(R.id.reminder_title, reminder.getTitle());
if (!useMiniLayout) {
views.setTextViewText(R.id.reminder_description, reminder.getDescription());
}
views.setTextViewText(R.id.reminder_time, reminder.getFormattedTime());
final Intent fillInIntent = new Intent();
final Bundle extras = new Bundle();
extras.putString(ReminderViewsService.OpenReminderId, reminder.getId());
fillInIntent.putExtras(extras);
views.setOnClickFillInIntent(R.id.reminder_item_btn, fillInIntent);
return views;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean hasStableIds() {
return true;
}
}

View File

@@ -0,0 +1,50 @@
package com.streetwriters.notesnook;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.widget.RemoteViews;
public class ReminderWidgetProvider extends AppWidgetProvider {
static String NewReminder = "com.streetwriters.notesnook.NewReminder";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_reminders);
updateAppWidget(context, appWidgetManager, appWidgetId, views);
}
}
private static Bundle getActivityOptionsBundle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
ActivityOptions activityOptions = ActivityOptions.makeBasic();
activityOptions.setPendingIntentBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
return activityOptions.toBundle();
} else
return null;
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, RemoteViews views) {
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE, getActivityOptionsBundle());
views.setPendingIntentTemplate(R.id.widget_list_view, pendingIntent);
Intent intent2 = new Intent(context, MainActivity.class);
intent2.putExtra(NewReminder, NewReminder);
PendingIntent pendingIntent2 = PendingIntent.getActivity(context, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, getActivityOptionsBundle());
views.setOnClickPendingIntent(R.id.add_button, pendingIntent2);
Intent intent3 = new Intent(context, ReminderViewsService.class);
intent3.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
views.setRemoteAdapter(R.id.widget_list_view, intent3);
views.setEmptyView(R.id.widget_list_view, R.id.empty_view);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}

View File

@@ -0,0 +1,89 @@
package com.streetwriters.notesnook.datatypes;
public class BaseItem {
private String id;
private String type;
private long dateModified;
private long dateCreated;
private Boolean migrated;
private Boolean remote;
private Boolean synced;
private Boolean deleted;
/**
* @deprecated only kept here for migration purposes
*/
private Object deleteReason; // Assuming never can be represented as Object
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public long getDateModified() {
return dateModified;
}
public void setDateModified(long dateModified) {
this.dateModified = dateModified;
}
public long getDateCreated() {
return dateCreated;
}
public void setDateCreated(long dateCreated) {
this.dateCreated = dateCreated;
}
public Boolean getMigrated() {
return migrated;
}
public void setMigrated(Boolean migrated) {
this.migrated = migrated;
}
public Boolean getRemote() {
return remote;
}
public void setRemote(Boolean remote) {
this.remote = remote;
}
public Boolean getSynced() {
return synced;
}
public void setSynced(Boolean synced) {
this.synced = synced;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public Object getDeleteReason() {
return deleteReason;
}
public void setDeleteReason(Object deleteReason) {
this.deleteReason = deleteReason;
}
}

View File

@@ -0,0 +1,122 @@
package com.streetwriters.notesnook.datatypes;
public class Note extends BaseItem {
private String title;
private String headline;
private String contentId;
private Boolean locked;
private boolean pinned;
private boolean favorite;
private boolean localOnly;
private boolean conflicted;
private boolean readonly;
private long dateEdited;
private Object dateDeleted; // Assuming null can be represented as Object
private Object itemType; // Assuming null can be represented as Object
private Object deletedBy; // Assuming null can be represented as Object
// Getters and Setters
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public String getContentId() {
return contentId;
}
public void setContentId(String contentId) {
this.contentId = contentId;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public boolean isPinned() {
return pinned;
}
public void setPinned(boolean pinned) {
this.pinned = pinned;
}
public boolean isFavorite() {
return favorite;
}
public void setFavorite(boolean favorite) {
this.favorite = favorite;
}
public boolean isLocalOnly() {
return localOnly;
}
public void setLocalOnly(boolean localOnly) {
this.localOnly = localOnly;
}
public boolean isConflicted() {
return conflicted;
}
public void setConflicted(boolean conflicted) {
this.conflicted = conflicted;
}
public boolean isReadonly() {
return readonly;
}
public void setReadonly(boolean readonly) {
this.readonly = readonly;
}
public long getDateEdited() {
return dateEdited;
}
public void setDateEdited(long dateEdited) {
this.dateEdited = dateEdited;
}
public Object getDateDeleted() {
return dateDeleted;
}
public void setDateDeleted(Object dateDeleted) {
this.dateDeleted = dateDeleted;
}
public Object getItemType() {
return itemType;
}
public void setItemType(Object itemType) {
this.itemType = itemType;
}
public Object getDeletedBy() {
return deletedBy;
}
public void setDeletedBy(Object deletedBy) {
this.deletedBy = deletedBy;
}
}

View File

@@ -0,0 +1,135 @@
package com.streetwriters.notesnook.datatypes;
import java.util.concurrent.TimeUnit;
public class Reminder extends BaseItem {
private String title;
private String description;
private String formattedTime;
private String priority; // "silent", "vibrate", "urgent"
private long date;
private String mode; // "repeat", "once", "permanent"
private String recurringMode; // "week", "month", "day", "year"
private int[] selectedDays;
private boolean localOnly;
private boolean disabled;
private long snoozeUntil;
// Getters and Setters
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPriority() {
return priority;
}
public void setPriority(String priority) {
this.priority = priority;
}
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public String getRecurringMode() {
return recurringMode;
}
public void setRecurringMode(String recurringMode) {
this.recurringMode = recurringMode;
}
public int[] getSelectedDays() {
return selectedDays;
}
public void setSelectedDays(int[] selectedDays) {
this.selectedDays = selectedDays;
}
public boolean isLocalOnly() {
return localOnly;
}
public void setLocalOnly(boolean localOnly) {
this.localOnly = localOnly;
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public long getSnoozeUntil() {
return snoozeUntil;
}
public void setSnoozeUntil(long snoozeUntil) {
this.snoozeUntil = snoozeUntil;
}
public String getFormattedTime() {
return formattedTime;
}
public void setFormattedTime(String formattedTime) {
this.formattedTime = formattedTime;
}
public String formatTime(long timeInMillis) {
long currentTime = System.currentTimeMillis();
long diff = timeInMillis - currentTime;
if (diff < TimeUnit.MINUTES.toMillis(1)) {
return "in " + (diff / 1000) + " seconds";
} else if (diff < TimeUnit.HOURS.toMillis(1)) {
long minutes = TimeUnit.MILLISECONDS.toMinutes(diff);
return "in " + minutes + " minute" + (minutes > 1 ? "s" : "");
} else if (diff < TimeUnit.DAYS.toMillis(1)) {
long hours = TimeUnit.MILLISECONDS.toHours(diff);
return "in " + hours + " hour" + (hours > 1 ? "s" : "");
} else if (diff < TimeUnit.DAYS.toMillis(2)) {
return "tomorrow";
} else if (diff < TimeUnit.DAYS.toMillis(7)) {
long days = TimeUnit.MILLISECONDS.toDays(diff);
return "in " + days + " day" + (days > 1 ? "s" : "");
} else if (diff < TimeUnit.DAYS.toMillis(30)) {
long weeks = TimeUnit.MILLISECONDS.toDays(diff) / 7;
return "in " + weeks + " week" + (weeks > 1 ? "s" : "");
} else if (diff < TimeUnit.DAYS.toMillis(365)) {
long months = TimeUnit.MILLISECONDS.toDays(diff) / 30;
return "in " + months + " month" + (months > 1 ? "s" : "");
} else {
long years = TimeUnit.MILLISECONDS.toDays(diff) / 365;
return "in " + years + " year" + (years > 1 ? "s" : "");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,37 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:padding="10dp"
android:theme="@style/ThemeOverlay.Notesnook.AppWidgetContainer">
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/widget_button"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/layout_bg"
android:paddingHorizontal="10dp"
android:elevation="5dp"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/add_note"
android:contentDescription="New note icon" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:textColor="@color/text"
android:textSize="16sp"
android:text="@string/take_a_quick_note" />
</LinearLayout>
</RelativeLayout>

View File

@@ -3,35 +3,39 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:padding="@dimen/widget_margin"
android:padding="10dp"
android:theme="@style/ThemeOverlay.Notesnook.AppWidgetContainer">
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/widget_button"
android:layout_height="50dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/layout_bg"
android:paddingHorizontal="10dp"
android:paddingVertical="10dp"
android:elevation="5dp"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/add_note"
android:contentDescription="New note icon" />
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:id="@+id/widget_title"
android:textColor="@color/text"
android:textSize="16sp"
android:text="@string/take_a_quick_note" />
android:textStyle="bold"
android:text="Widget unconfigured" />
<TextView
android:id="@+id/widget_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:textColor="@color/text"
android:textSize="14sp"
android:text="Configure this widget to show a note here." />
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,8 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="No upcoming reminders"
android:textSize="16sp"
android:textColor="@android:color/darker_gray"
android:gravity="center" />

View File

@@ -0,0 +1,28 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/reminder_item_btn">
<TextView
android:id="@+id/reminder_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="@color/text"
android:textSize="16sp" />
<TextView
android:id="@+id/reminder_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text"
android:textSize="14sp" />
<TextView
android:id="@+id/reminder_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@color/text" />
</LinearLayout>

View File

@@ -0,0 +1,21 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/reminder_item_btn">
<TextView
android:id="@+id/reminder_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="@color/text"
android:textSize="16sp" />
<TextView
android:id="@+id/reminder_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@color/text" />
</LinearLayout>

View File

@@ -0,0 +1,64 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/layout_bg"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="12dp"
android:layout_gravity="center"
android:paddingTop="12dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginTop="2dp"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Upcoming Reminders"/>
<ImageButton
android:layout_width="30dp"
android:id="@+id/add_button"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:background="@drawable/ic_newnote" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="8dp"
android:background="@color/border" />
<ListView
android:id="@+id/widget_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@color/border"
android:paddingBottom="12dp"
android:paddingHorizontal="12dp"
android:dividerHeight="1dp" />
<LinearLayout
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAlignment="center"
android:gravity="center"
android:text="Tap on + to add reminder"/>
</LinearLayout>
</LinearLayout>

View File

@@ -6,5 +6,6 @@
<color name="light_blue_900">#FF01579B</color>
<color name="bootsplash_background">#1f1f1f</color>
<color name="background">#1D1D1D</color>
<color name="border">#2E2E2E</color>
<color name="text">#B4B4B4</color>
</resources>

View File

@@ -5,6 +5,7 @@
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
<color name="bootsplash_background">#FFFFFF</color>
<color name="background">#FFFFFF</color>
<color name="text">#000000</color>
<color name="background">#D8000000</color>
<color name="border">#CCCCCC</color>
<color name="text">#1D1D1D</color>
</resources>

View File

@@ -4,4 +4,9 @@
<string name="appwidget_text">EXAMPLE</string>
<string name="add_widget">Add widget</string>
<string name="take_a_quick_note">Take a quick note.</string>
<string name="reminders">Quick overview of upcoming reminders</string>
<string name="reminders_title">Reminders</string>
<string name="note">Note</string>
<string name="note_description">Add a note to home screen</string>
<string name="quick_note">Quick note</string>
</resources>

View File

@@ -1,9 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/note_widget"
android:initialLayout="@layout/note_widget"
android:minWidth="50dp"
android:initialKeyguardLayout="@layout/new_note_widget"
android:initialLayout="@layout/new_note_widget"
android:minWidth="400dp"
android:minHeight="50dp"
android:minResizeWidth="50dp"
android:minResizeHeight="50dp"
android:description="@string/take_a_quick_note"
android:targetCellWidth="5"
android:targetCellHeight="1"
android:previewImage="@drawable/widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"

View File

@@ -2,11 +2,16 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/note_widget"
android:initialLayout="@layout/note_widget"
android:minWidth="50dp"
android:configure="com.streetwriters.notesnook.NotePreviewConfigureActivity"
android:widgetFeatures="reconfigurable"
android:minResizeWidth="100dp"
android:minResizeHeight="50dp"
android:minWidth="400dp"
android:description="@string/note_description"
android:minHeight="50dp"
android:targetCellWidth="5"
android:targetCellHeight="1"
android:previewImage="@drawable/widget_preview"
android:previewImage="@drawable/note_widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"/>

View File

@@ -0,0 +1,14 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_reminders"
android:minWidth="400dp"
android:minHeight="100dp"
android:minResizeWidth="400dp"
android:minResizeHeight="50dp"
android:description="@string/reminders"
android:targetCellWidth="5"
android:targetCellHeight="2"
android:resizeMode="horizontal|vertical"
android:previewImage="@drawable/reminder_preview"
android:updatePeriodMillis="1024"
android:widgetCategory="home_screen"
/>

Some files were not shown because too many files have changed in this diff Show More