diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 379f9048..94a25f7f 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,5 @@
-
\ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
index d45ca996..d06dfea7 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/app/app.json b/packages/app/app.json
index 34b9efe1..b7e45508 100644
--- a/packages/app/app.json
+++ b/packages/app/app.json
@@ -48,6 +48,14 @@
]
}
],
+ [
+ "expo-build-properties",
+ {
+ "ios": {
+ "deploymentTarget": "17.0"
+ }
+ }
+ ],
"sentry-expo",
[
"expo-router",
diff --git a/packages/app/expoPlugin/ios/ORWidgetReloadBridge.m b/packages/app/expoPlugin/ios/ORWidgetReloadBridge.m
new file mode 100644
index 00000000..1f2397ac
--- /dev/null
+++ b/packages/app/expoPlugin/ios/ORWidgetReloadBridge.m
@@ -0,0 +1,17 @@
+//
+// ORWidgetReloadBridge.m
+// Orbit
+//
+// Created by Andy Matuschak on 2024-07-12.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RCT_EXTERN_MODULE(WidgetReloadBridge, NSObject)
+RCT_EXTERN_METHOD(reloadTimelines)
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/app/expoPlugin/ios/ORWidgetReloadBridge.swift b/packages/app/expoPlugin/ios/ORWidgetReloadBridge.swift
new file mode 100644
index 00000000..73a1515b
--- /dev/null
+++ b/packages/app/expoPlugin/ios/ORWidgetReloadBridge.swift
@@ -0,0 +1,16 @@
+//
+// ORWidgetReloadBridge.swift
+// Orbit
+//
+// Created by Andy Matuschak on 2024-07-12.
+//
+
+import Foundation
+import WidgetKit
+
+@objc(WidgetReloadBridge) class WidgetReloadBridge: NSObject {
+ @objc public func reloadTimelines() {
+ WidgetCenter.shared.reloadAllTimelines()
+ print("Reloading timelines")
+ }
+}
diff --git a/packages/app/expoPlugin/withWidgetPluginFixes.js b/packages/app/expoPlugin/withWidgetPluginFixes.js
index 4dbaa75b..6cf346cd 100644
--- a/packages/app/expoPlugin/withWidgetPluginFixes.js
+++ b/packages/app/expoPlugin/withWidgetPluginFixes.js
@@ -1,7 +1,18 @@
-const { withMod } = require("expo/config-plugins");
+const { withMod, withXcodeProject } = require("expo/config-plugins");
const { PBXBuildFile, PBXShellScriptBuildPhase } = require("@bacons/xcode");
const path = require("path");
+const { addSourceFile } = require("./util");
module.exports = function withWidgetPluginFixes(config) {
+ config = withXcodeProject(config, async (config) => {
+ for (const file of [
+ "ORWidgetReloadBridge.m",
+ "ORWidgetReloadBridge.swift",
+ ]) {
+ addSourceFile(config, file);
+ }
+ return config;
+ });
+
config = withMod(config, {
platform: "ios",
// Bit of a hack: we're hooking into @bacons/apple-target's mod here. This string must match the one in https://github.com/EvanBacon/expo-apple-targets/blob/afd63577f43aa50665f2c31ed4ed14c052bc57bd/packages/apple-targets/src/withXcparse.ts.
diff --git a/packages/app/package.json b/packages/app/package.json
index 09a9a841..4d2aed53 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -28,6 +28,7 @@
"base-64": "^1.0.0",
"expo": "~51.0.17",
"expo-application": "~5.9.1",
+ "expo-build-properties": "^0.12.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-device": "~6.0.2",
diff --git a/packages/app/src/reviewSession/ReviewSession.tsx b/packages/app/src/reviewSession/ReviewSession.tsx
index 6fea2072..cb1b85e7 100644
--- a/packages/app/src/reviewSession/ReviewSession.tsx
+++ b/packages/app/src/reviewSession/ReviewSession.tsx
@@ -26,7 +26,7 @@ import {
} from "@withorbit/ui";
import { useLocalSearchParams } from "expo-router";
import React, { useEffect, useRef, useState } from "react";
-import { Platform, Text, View } from "react-native";
+import { NativeModules, Platform, Text, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { AuthenticationClient } from "../authentication/index.js";
import {
@@ -39,6 +39,8 @@ import { useReviewSessionManager } from "../reviewSessionManager.js";
import { useAPIClient } from "../util/useAPIClient.js";
import { LoadingScreen } from "./LoadingScreen.js";
+const { WidgetReloadBridge } = NativeModules;
+
export function useDatabaseManager(
authenticationClient: AuthenticationClient,
): DatabaseManager2 | null {
@@ -92,6 +94,7 @@ function persistMarking({
.recordEvents([event])
.then(() => {
console.log("[Performance] Log written", Date.now() / 1000.0);
+ WidgetReloadBridge.reloadTimelines();
})
.catch((error) => {
console.error("Couldn't commit", reviewItem.task.id, error);
@@ -304,6 +307,7 @@ export default function ReviewSession() {
])
.then(() => {
console.log("Wrote delete event", Date.now() / 1000.0);
+ WidgetReloadBridge.reloadTimelines();
})
.catch((error) => {
console.error("Couldn't commit delete event", error);
diff --git a/packages/app/targets/widgets/AppIntents.swift b/packages/app/targets/widgets/AppIntents.swift
deleted file mode 100644
index 1f32d7a1..00000000
--- a/packages/app/targets/widgets/AppIntents.swift
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// AppIntents.swift
-// OrbitWidgetExtension
-//
-// Created by Andy Matuschak on 2024-06-26.
-//
-
-import Foundation
-import AppIntents
-
-struct ConfigurationAppIntent: WidgetConfigurationIntent {
- static var title: LocalizedStringResource = "Configuration"
-}
diff --git a/packages/app/targets/widgets/Widget.swift b/packages/app/targets/widgets/Widget.swift
index 4e6cc8b9..359bcd31 100644
--- a/packages/app/targets/widgets/Widget.swift
+++ b/packages/app/targets/widgets/Widget.swift
@@ -27,38 +27,42 @@ struct ReviewState {
var transientState = ReviewState()
let bridge = Bridge()
-struct Provider: AppIntentTimelineProvider {
- func placeholder(in context: Context) -> Entry {
- Entry(item: .placeholder, isShowingAnswer: false, date: Date())
- }
-
- func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> Entry {
- Entry(item: .placeholder, isShowingAnswer: false, date: Date())
- }
-
- func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline {
- var entries: [Entry] = []
- print("REFRESH TIMELINE")
-
- // transientState.queue = [.placeholder, .placeholder]
- if transientState.queue == nil {
- transientState.queue = await bridge.generateReviewQueue()
+struct Provider: TimelineProvider {
+ func getSnapshot(in context: Context, completion: @escaping @Sendable (Entry) -> Void) {
+ Task {
+ let queue = await bridge.generateReviewQueue()
+ completion(Entry(item: queue[0], isShowingAnswer: false, date: Date()))
}
+ }
+
+ func getTimeline(in context: Context, completion: @escaping @Sendable (Timeline) -> Void) {
+ Task {
+ var entries: [Entry] = []
+ print("REFRESH TIMELINE")
+
+// if transientState.queue == nil {
+ transientState.queue = await bridge.generateReviewQueue()
+// }
+
+ let queue = transientState.queue!.filter { item in !transientState.reviewedTaskIDs.contains(item.task.id) }
+
+ let currentDate = Date()
+ for hourOffset in 0.. Entry {
+ Entry(item: .placeholder, isShowingAnswer: false, date: Date())
}
}
@@ -158,7 +162,7 @@ struct PromptTextStyle: ViewModifier {
let fontStyle: OrbitFont.Type
init(text: String) {
self.fontStyle = switch text.count {
- case 0 ... 80:
+ case 0 ... 70:
OrbitPromptMedium.self
default:
OrbitPromptSmall.self
@@ -295,7 +299,7 @@ struct OrbitHomeScreen: Widget {
let kind: String = "OrbitHomeScreen"
var body: some WidgetConfiguration {
- AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
+ StaticConfiguration(kind: kind, provider: Provider()) { entry in
let colorPalette = colorPalette(for: entry.item)
PromptView(item: entry.item, isShowingAnswer: entry.isShowingAnswer)
.containerBackground(colorPalette.backgroundColor, for: .widget)