Skip to content

Commit

Permalink
refactor stores, lint files
Browse files Browse the repository at this point in the history
  • Loading branch information
lukesthl committed Jan 3, 2024
1 parent 9d5c695 commit de04970
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 108 deletions.
5 changes: 3 additions & 2 deletions apps/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { TamaguiProvider, useTheme as useThemeTamagui } from "tamagui";
import "../data/logger";

import { ThemeProvider, useTheme } from "../components/theme-provider";
import { clearOpenedApp, clearShortcutListener, listenForShortcut } from "../data/shortcut.listener";
import { clearShortcutListener, listenForShortcut } from "../data/shortcut.listener";
import { ShortCutPayload } from "../data/shortcut.payload";
import config from "../tamagui.config";

export { ErrorBoundary } from "expo-router";
Expand Down Expand Up @@ -58,7 +59,7 @@ function RootLayoutNav() {
console.log("App has come to the foreground!");
} else if (appState.current.match(/active/) && nextAppState === "background") {
clearShortcutListener();
void clearOpenedApp();
void ShortCutPayload.clear();
console.log("App has come to the background!");
}
appState.current = nextAppState;
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/app/break/[appShortcutName].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Break = observer(() => {
setLoaded(true);
});
void OverviewStore.init();
}, [loaded, searchParams.appShortcutName]);
}, [loaded, searchParams.appShortcutName, searchParams.timestamp]);

const animationProgress = useRef(new Animated.Value(0));
const selectedApp = BreakStore.app;
Expand Down
14 changes: 7 additions & 7 deletions apps/expo/app/setup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ const Setup = observer(() => {
</View>
<View marginTop={"$1.5"}>
<H4 color="$text11" lineHeight={20}>
Select "App"-Trigger
Select &quot;App&quot;-Trigger
</H4>
<Paragraph color="$text11">Scroll down and select "App" as the trigger.</Paragraph>
<Paragraph color="$text11">Scroll down and select &quot;App&quot; as the trigger.</Paragraph>
</View>
</XStack>
</ShadowCard>
Expand All @@ -125,10 +125,10 @@ const Setup = observer(() => {
<H4 color="$text11" lineHeight={20}>
Configure the trigger
</H4>
<Paragraph color="$text11">Select "Choose" and search for the app you want to use.</Paragraph>
<Paragraph color="$text11">Select &quot;Choose&quot; and search for the app you want to use.</Paragraph>
<Paragraph color="$text11">Info: You need to create a trigger for every app you want to use.</Paragraph>
<Paragraph color="$text11">Select "open directly"</Paragraph>
<Paragraph color="$text11">Select "Next" when you are done.</Paragraph>
<Paragraph color="$text11">Select &quot;open directly&quot;</Paragraph>
<Paragraph color="$text11">Select &quot;Next&quot; when you are done.</Paragraph>
</View>
</XStack>
</ShadowCard>
Expand All @@ -149,9 +149,9 @@ const Setup = observer(() => {
</View>
<View marginTop={"$1.5"}>
<H4 color="$text11" lineHeight={22}>
Select "digital break" as the action
Select &quot;digital break&quot; as the action
</H4>
<Paragraph color="$text11">Search for "digital break" and select it.</Paragraph>
<Paragraph color="$text11">Search for &quot;digital break&quot; and select it.</Paragraph>
</View>
</XStack>
</ShadowCard>
Expand Down
58 changes: 4 additions & 54 deletions apps/expo/data/break.store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Vibration } from "react-native";
import Constants, { AppOwnership } from "expo-constants";
import * as Haptics from "expo-haptics";
import * as Linking from "expo-linking";
import { router } from "expo-router";
import { makeAutoObservable } from "mobx";
Expand All @@ -9,7 +7,7 @@ import * as ExpoExitApp from "../../../packages/expo-exit-app";
import { AppStatisticsStore } from "./app.statistics";
import type { App } from "./apps";
import { AppsStore, deepLinks } from "./apps";
import { clearOpenedApp, updateOpenedApp } from "./shortcut.listener";
import { ShortCutPayload } from "./shortcut.payload";

const isRunningInExpoGo = Constants.appOwnership === AppOwnership.Expo;

Expand Down Expand Up @@ -54,61 +52,14 @@ export class BreakStoreSingleton {
void this.appStatisticsStore.trackEvent({ appId: app.id, type: "break-start" });
}
}
private getHapticImpactEnum = (impact: string): Haptics.ImpactFeedbackStyle | undefined => {
switch (impact) {
case "heavy":
return Haptics.ImpactFeedbackStyle.Heavy;
case "medium":
return Haptics.ImpactFeedbackStyle.Medium;
case "light":
return Haptics.ImpactFeedbackStyle.Light;
}
};

public async hapticImpact(): Promise<void> {
const pattern: ("light" | "medium" | "heavy" | "vibrate" | number)[] = [];
const duration = this.app?.settings.breakDurationSeconds ?? 0;
const durationInMs = duration * 1;
for (let i = 0; i < durationInMs; ++i) {
if (i < duration / 2) {
pattern.push("light");
} else {
pattern.push("medium");
}
pattern.push(100);
}
console.log("Haptic pattern", pattern);
for (let i = 0; i < pattern.length; ++i) {
const e = pattern[i];
if (i % 2 === 0) {
// Vibration length, always 400 for iOS
if (typeof e === "number") {
Vibration.vibrate(e);
await new Promise((res) => setTimeout(res, e));
// Default
} else if (e === "vibrate" || !e) {
Vibration.vibrate();
// Use native impact type
} else {
console.log("Haptic impact", e);
await Haptics.impactAsync(this.getHapticImpactEnum(e) ?? Haptics.ImpactFeedbackStyle.Medium);
}
// Await for the pause
} else {
if (typeof e !== "number") return;
await new Promise((res) => setTimeout(res, e));
}
}
}

public async openApp(): Promise<void> {
if (!this.app) {
throw new Error("App not initialized");
}
await this.appStatisticsStore.trackEvent({ appId: this.app.id, type: "app-reopen" });
await updateOpenedApp(this.app.key, "app-reopen");
await new Promise((resolve) => setTimeout(resolve, 500));
// await AsyncStorage.setItem("openedApp", `${this.app.key}_${Date.now()}_app-reopen`);
await ShortCutPayload.update(this.app.key, "app-reopen");
await new Promise((resolve) => setTimeout(resolve, 500)); // app intent isnt fast enough
await Linking.openURL(deepLinks[this.app.key as keyof typeof deepLinks]);
router.replace("/");
}
Expand All @@ -118,8 +69,7 @@ export class BreakStoreSingleton {
throw new Error("App not initialized");
}
await this.appStatisticsStore.trackEvent({ appId: this.app.id, type: "app-close" });
// await AsyncStorage.setItem("openedApp", `${this.app.key}_${Date.now()}_app-reopen`);
await clearOpenedApp();
await ShortCutPayload.clear();
ExpoExitApp.exit();
}

Expand Down
48 changes: 4 additions & 44 deletions apps/expo/data/shortcut.listener.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import * as FileSystem from "expo-file-system";

import { appConfig } from "../constants/app.config";
import { ShortCutPayload } from "./shortcut.payload";

const MAX_TRY_COUNT = 10;
let intervalId: NodeJS.Timeout | null = null;
const storageKey = "openedApp";
const pathSplitted = FileSystem.documentDirectory?.split("/");
const appPath = pathSplitted?.slice(0, pathSplitted.length - 2).join("/");
const dataPath = `${appPath}/Library/Application Support/${appConfig.bundleIdentifier}/RCTAsyncLocalStorage_V1/appintent.json`;

// why FileSystem? because AsyncStorage doesnt work in combination with the App Intent.
// It seems like AsyncStorage caches the value and not directly writes it to the file system.
// It seems like AsyncStorage caches the value in memory and not directly writes it to the file system.
export const listenForShortcut = async (): Promise<{ app: string; timestamp: number }> => {
let tryCount = 0;
return new Promise((resolve, reject) => {
const time = new Date().getTime();
intervalId = setInterval(() => {
try {
getOpenedApp()
ShortCutPayload.getPayload()
.then((appPayload) => {
if (appPayload && appPayload.event === "break-start") {
clearInterval(intervalId ?? 0);
Expand All @@ -41,11 +35,9 @@ export const listenForShortcut = async (): Promise<{ app: string; timestamp: num
}
});
} catch (error) {
console.log("maybe something went wrong");
console.log(JSON.stringify(error));
console.log(error);
}
}, 500);
console.log("interval after interval", JSON.stringify(intervalId));
});
};

Expand All @@ -54,35 +46,3 @@ export const clearShortcutListener = () => {
clearInterval(intervalId);
}
};

export const getOpenedApp = async (): Promise<{ app: string; timestamp: string; event: string } | null> => {
const string = await FileSystem.readAsStringAsync(dataPath);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const manifest = JSON.parse(string);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const openedAppPayload = manifest[storageKey] as string | undefined;
if (openedAppPayload) {
const [openedApp, timestamp, event] = openedAppPayload.split("_") as [string, string, string];
return { app: openedApp, timestamp, event };
} else {
return null;
}
};

export const updateOpenedApp = async (app: string, event: string) => {
const string = await FileSystem.readAsStringAsync(dataPath);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const manifest = JSON.parse(string);
const withoutApp = manifest as Record<string, unknown>;
withoutApp.openedApp = `${app}_${Date.now()}_${event}`;
await FileSystem.writeAsStringAsync(dataPath, JSON.stringify(withoutApp));
};

export const clearOpenedApp = async () => {
const string = await FileSystem.readAsStringAsync(dataPath);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const manifest = JSON.parse(string);
const withoutApp = manifest as Record<string, unknown>;
delete withoutApp.openedApp;
await FileSystem.writeAsStringAsync(dataPath, JSON.stringify(withoutApp));
};
41 changes: 41 additions & 0 deletions apps/expo/data/shortcut.payload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as FileSystem from "expo-file-system";

import { appConfig } from "../constants/app.config";

class ShortCutPayloadSingleton {
private readonly storageKey = "openedApp";
private pathSplitted = FileSystem.documentDirectory?.split("/");
private appPath = this.pathSplitted?.slice(0, this.pathSplitted.length - 2).join("/");
private dataPath = `${this.appPath}/Library/Application Support/${appConfig.bundleIdentifier}/RCTAsyncLocalStorage_V1/appintent.json`;

private loadAppIntentPayload = async (): Promise<Record<string, unknown>> => {
const string = await FileSystem.readAsStringAsync(this.dataPath);
const payload = JSON.parse(string) as Record<string, unknown>;
return payload;
};

public getPayload = async (): Promise<{ app: string; timestamp: string; event: string } | null> => {
const payload = await this.loadAppIntentPayload();
const openedAppPayload = payload[this.storageKey] as string | undefined;
if (openedAppPayload) {
const [openedApp, timestamp, event] = openedAppPayload.split("_") as [string, string, string];
return { app: openedApp, timestamp, event };
} else {
return null;
}
};

public update = async (app: string, event: string) => {
const appIntentPayload = await this.loadAppIntentPayload();
appIntentPayload.openedApp = `${app}_${Date.now()}_${event}`;
await FileSystem.writeAsStringAsync(this.dataPath, JSON.stringify(appIntentPayload));
};

public clear = async () => {
const appIntentPayload = await this.loadAppIntentPayload();
delete appIntentPayload.openedApp;
await FileSystem.writeAsStringAsync(this.dataPath, JSON.stringify(appIntentPayload));
};
}

export const ShortCutPayload = new ShortCutPayloadSingleton();
6 changes: 6 additions & 0 deletions packages/shortcuts-generator/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ const generateShortcuts = async () => {
);
};

if (os.platform() !== "darwin") {
console.error("ERROR: shortcut generation stopped because you are not on macOS. Signing shortcuts requires macOS.");
process.exit(0);
}

const time = new Date().getTime();

void generateShortcuts().then(() => {
console.log(`took ${new Date().getTime() - time}ms`);
});
Expand Down

0 comments on commit de04970

Please sign in to comment.