mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
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:
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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: (
|
||||
|
||||
@@ -528,7 +528,9 @@ export const AttachmentDialog = ({
|
||||
setAttachments(results);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(console.log);
|
||||
.catch(() => {
|
||||
/* empty */
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -180,7 +180,7 @@ AttachImage.present = (response: ImageType[], context?: string) => {
|
||||
close={close}
|
||||
onAttach={(result) => {
|
||||
resolved = true;
|
||||
console.log("closing");
|
||||
|
||||
resolve(result);
|
||||
close?.();
|
||||
}}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ export const Header = ({
|
||||
onSearch
|
||||
}: {
|
||||
onLeftMenuButtonPress?: () => void;
|
||||
renderedInRoute: RouteName;
|
||||
renderedInRoute?: RouteName;
|
||||
id?: string;
|
||||
title: string;
|
||||
headerRightButtons?: HeaderRightButton[];
|
||||
|
||||
@@ -41,7 +41,7 @@ export const RightMenus = ({
|
||||
onSearch
|
||||
}: {
|
||||
headerRightButtons?: HeaderRightButton[];
|
||||
renderedInRoute: RouteName;
|
||||
renderedInRoute?: RouteName;
|
||||
id?: string;
|
||||
onPressDefaultRightButton?: () => void;
|
||||
search?: boolean;
|
||||
|
||||
@@ -41,7 +41,7 @@ export const Title = ({
|
||||
isHiddenOnRender?: boolean;
|
||||
accentColor?: string;
|
||||
isBeta?: boolean;
|
||||
renderedInRoute: string;
|
||||
renderedInRoute?: string;
|
||||
id?: string;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -100,7 +100,6 @@ export const AddNotebookSheet = ({
|
||||
eSendEvent(eOnNotebookUpdated, parent);
|
||||
if (notebook) {
|
||||
setImmediate(() => {
|
||||
console.log(parent, notebook.id);
|
||||
eSendEvent(eOnNotebookUpdated, notebook.id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -62,7 +62,9 @@ export const ShareComponent = ({ uri, name, padding }) => {
|
||||
showOpenWithDialog: true,
|
||||
showAppsSuggestions: true,
|
||||
shareFile: true
|
||||
}).catch(console.log);
|
||||
}).catch(() => {
|
||||
/* empty */
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -196,7 +196,6 @@ export const useTotalNotes = (type: "notebook" | "tag" | "color") => {
|
||||
}
|
||||
setTotalNotesById(totalNotesById);
|
||||
});
|
||||
console.log("useTotalNotes.getTotalNotes");
|
||||
},
|
||||
[type]
|
||||
);
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -94,4 +94,5 @@ export type AppState = {
|
||||
editing: boolean;
|
||||
movedAway: boolean;
|
||||
timestamp: number;
|
||||
noteId?: string;
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
169
apps/mobile/app/screens/note-preview-configure/index.tsx
Normal file
169
apps/mobile/app/screens/note-preview-configure/index.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,6 @@ const NotesPage = ({
|
||||
setLoadingNotes(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Error loading notes", params.current?.title, e, e.stack);
|
||||
setLoadingNotes(false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,9 +160,7 @@ export default function DebugLogs() {
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
} catch (e) {}
|
||||
}, [currentLog?.logs]);
|
||||
|
||||
const copyLogs = React.useCallback(() => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -123,7 +123,6 @@ export type PresentSheetOptions = {
|
||||
};
|
||||
|
||||
export function presentSheet(data: Partial<PresentSheetOptions>) {
|
||||
console.log("PRESENTING...");
|
||||
eSendEvent(eOpenSheet, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
73
apps/mobile/app/services/intent.ts
Normal file
73
apps/mobile/app/services/intent.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
45
apps/mobile/app/services/note-preview-widget.ts
Normal file
45
apps/mobile/app/services/note-preview-widget.ts
Normal 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));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -22,6 +22,7 @@ class MainApplication : Application(), ReactApplication {
|
||||
add(NNativeModulePackage());
|
||||
}
|
||||
|
||||
|
||||
override fun getJSMainModuleName(): String = "index"
|
||||
|
||||
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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" />
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"/>
|
||||
@@ -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
Reference in New Issue
Block a user