From eccf27425c52fcbf39c77543c79c6906798ee55e Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Mon, 29 Dec 2025 02:03:37 -0500 Subject: [PATCH 1/6] fix(mobile): fix infinite spinner bug + fix android dark mode bug --- apps/mobile/store/auth.ts | 46 +++++++++++++++++++++++---------------- apps/mobile/store/data.ts | 4 ++-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/mobile/store/auth.ts b/apps/mobile/store/auth.ts index b04178f2..c2e7f760 100644 --- a/apps/mobile/store/auth.ts +++ b/apps/mobile/store/auth.ts @@ -3,13 +3,10 @@ import * as SecureStore from "expo-secure-store"; import { router } from "expo-router"; import { MobileAuth } from "@linkwarden/types"; import { Alert } from "react-native"; -import * as FileSystem from "expo-file-system"; import { queryClient } from "@/lib/queryClient"; import { mmkvPersister } from "@/lib/queryPersister"; import { clearCache } from "@/lib/cache"; -const CACHE_DIR = FileSystem.documentDirectory + "archivedData/"; - type AuthStore = { auth: MobileAuth; signIn: ( @@ -78,31 +75,42 @@ const useAuthStore = create((set) => ({ } }); } else { - await fetch(instance + "/api/v1/session", { - method: "POST", - body: JSON.stringify({ username, password }), - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { + try { + const res = await Promise.race([ + fetch(`${instance}/api/v1/session`, { + method: "POST", + body: JSON.stringify({ username, password }), + headers: { "Content-Type": "application/json" }, + }), + new Promise((_, reject) => + setTimeout(() => reject(new Error("TIMEOUT")), 30000) + ), + ]); + if (res.ok) { const data = await res.json(); const session = (data as any).response.token; + await SecureStore.setItemAsync("TOKEN", session); await SecureStore.setItemAsync("INSTANCE", instance); - set({ - auth: { - session, - instance, - status: "authenticated", - }, - }); - + set({ auth: { session, instance, status: "authenticated" } }); router.replace("/(tabs)/dashboard"); } else { Alert.alert("Error", "Invalid credentials"); } - }); + } catch (err: any) { + if (err?.message === "TIMEOUT") { + Alert.alert( + "Request timed out", + "Unable to reach the server in time. Please check your network configuration and try again." + ); + } else { + Alert.alert( + "Network error", + "Could not connect to the server. Please check your network configuration and try again." + ); + } + } } }, signOut: async () => { diff --git a/apps/mobile/store/data.ts b/apps/mobile/store/data.ts index b3a59065..c9ba3ac0 100644 --- a/apps/mobile/store/data.ts +++ b/apps/mobile/store/data.ts @@ -15,13 +15,13 @@ const useDataStore = create((set, get) => ({ hasShareIntent: false, url: "", }, - theme: "light", + theme: "system", preferredBrowser: "app", }, setData: async () => { const dataString = JSON.parse((await AsyncStorage.getItem("data")) || "{}"); - colorScheme.set(dataString.theme || "light"); + colorScheme.set(dataString.theme || "system"); if (dataString) set((state) => ({ data: { ...state.data, ...dataString } })); From cf844749211518d76782fcfcbcc9d82d5ab0b2f7 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Wed, 31 Dec 2025 08:57:46 -0500 Subject: [PATCH 2/6] fix infinite loading bug + enable corepack during eas submit --- apps/mobile/app/(tabs)/collections/index.tsx | 2 +- apps/mobile/app/(tabs)/dashboard/_layout.tsx | 4 +- apps/mobile/app/(tabs)/dashboard/index.tsx | 47 ++++++++++++++----- apps/mobile/app/(tabs)/tags/index.tsx | 2 +- .../components/ActionSheets/AddLinkSheet.tsx | 2 +- .../components/ActionSheets/EditLinkSheet.tsx | 2 +- .../ActionSheets/NewCollectionSheet.tsx | 2 +- apps/mobile/components/Links.tsx | 2 +- apps/mobile/components/Modals/AddLink.tsx | 17 ------- apps/mobile/eas.json | 1 + package.json | 4 -- 11 files changed, 43 insertions(+), 42 deletions(-) delete mode 100644 apps/mobile/components/Modals/AddLink.tsx diff --git a/apps/mobile/app/(tabs)/collections/index.tsx b/apps/mobile/app/(tabs)/collections/index.tsx index 36c082f6..f13a58a0 100644 --- a/apps/mobile/app/(tabs)/collections/index.tsx +++ b/apps/mobile/app/(tabs)/collections/index.tsx @@ -44,7 +44,7 @@ export default function CollectionsScreen() { collapsableChildren={false} > {collections.isLoading ? ( - + Loading... diff --git a/apps/mobile/app/(tabs)/dashboard/_layout.tsx b/apps/mobile/app/(tabs)/dashboard/_layout.tsx index 72a0407d..c129eafc 100644 --- a/apps/mobile/app/(tabs)/dashboard/_layout.tsx +++ b/apps/mobile/app/(tabs)/dashboard/_layout.tsx @@ -27,8 +27,8 @@ export default function Layout() { Platform.OS === "ios" ? "transparent" : colorScheme === "dark" - ? rawTheme["dark"]["base-100"] - : "white", + ? rawTheme["dark"]["base-100"] + : "white", }, }} > diff --git a/apps/mobile/app/(tabs)/dashboard/index.tsx b/apps/mobile/app/(tabs)/dashboard/index.tsx index ffb5ff56..19f734c1 100644 --- a/apps/mobile/app/(tabs)/dashboard/index.tsx +++ b/apps/mobile/app/(tabs)/dashboard/index.tsx @@ -1,4 +1,11 @@ -import { Platform, ScrollView, StyleSheet } from "react-native"; +import { + ActivityIndicator, + Platform, + ScrollView, + StyleSheet, + Text, + View, +} from "react-native"; import React, { useEffect, useMemo, useState } from "react"; import { useDashboardData } from "@linkwarden/router/dashboardData"; import useAuthStore from "@/store/auth"; @@ -53,22 +60,36 @@ export default function DashboardScreen() { }); }, [dashboardSections]); + const [pullRefreshing, setPullRefreshing] = useState(false); + + const onRefresh = async () => { + setPullRefreshing(true); + try { + await Promise.all([ + dashboardData.refetch(), + userData.refetch(), + collectionsData.refetch(), + tagsData.refetch(), + ]); + } finally { + setPullRefreshing(false); + } + }; + + if (orderedSections.length === 0 && dashboardData.isLoading) + return ( + + + Loading... + + ); + return ( { - dashboardData.refetch(); - userData.refetch(); - collectionsData.refetch(); - tagsData.refetch(); - }} + refreshing={pullRefreshing} + onRefresh={onRefresh} progressBackgroundColor={ rawTheme[colorScheme as ThemeName]["base-200"] } diff --git a/apps/mobile/app/(tabs)/tags/index.tsx b/apps/mobile/app/(tabs)/tags/index.tsx index ff20d7d6..12bceaf7 100644 --- a/apps/mobile/app/(tabs)/tags/index.tsx +++ b/apps/mobile/app/(tabs)/tags/index.tsx @@ -42,7 +42,7 @@ export default function TagsScreen() { collapsableChildren={false} > {tags.isLoading ? ( - + Loading... diff --git a/apps/mobile/components/ActionSheets/AddLinkSheet.tsx b/apps/mobile/components/ActionSheets/AddLinkSheet.tsx index 12b33731..c45e80f3 100644 --- a/apps/mobile/components/ActionSheets/AddLinkSheet.tsx +++ b/apps/mobile/components/ActionSheets/AddLinkSheet.tsx @@ -1,4 +1,4 @@ -import { Alert, Platform, Text, View } from "react-native"; +import { Alert, Text, View } from "react-native"; import { useRef, useState } from "react"; import ActionSheet, { ActionSheetRef } from "react-native-actions-sheet"; import Input from "@/components/ui/Input"; diff --git a/apps/mobile/components/ActionSheets/EditLinkSheet.tsx b/apps/mobile/components/ActionSheets/EditLinkSheet.tsx index c7d82938..531ed6ca 100644 --- a/apps/mobile/components/ActionSheets/EditLinkSheet.tsx +++ b/apps/mobile/components/ActionSheets/EditLinkSheet.tsx @@ -1,4 +1,4 @@ -import { View, Text, Alert, Platform } from "react-native"; +import { View, Text, Alert } from "react-native"; import { useCallback, useEffect, useMemo, useState } from "react"; import ActionSheet, { FlatList, diff --git a/apps/mobile/components/ActionSheets/NewCollectionSheet.tsx b/apps/mobile/components/ActionSheets/NewCollectionSheet.tsx index 32aa3070..3a65f54c 100644 --- a/apps/mobile/components/ActionSheets/NewCollectionSheet.tsx +++ b/apps/mobile/components/ActionSheets/NewCollectionSheet.tsx @@ -1,4 +1,4 @@ -import { Alert, Platform, Text, View } from "react-native"; +import { Alert, Text, View } from "react-native"; import { useRef, useState } from "react"; import ActionSheet, { ActionSheetRef } from "react-native-actions-sheet"; import Input from "@/components/ui/Input"; diff --git a/apps/mobile/components/Links.tsx b/apps/mobile/components/Links.tsx index 8c7f6785..88108796 100644 --- a/apps/mobile/components/Links.tsx +++ b/apps/mobile/components/Links.tsx @@ -28,7 +28,7 @@ export default function Links({ links, data }: Props) { const [promptedRefetch, setPromptedRefetch] = useState(false); return data.isLoading ? ( - + Loading... diff --git a/apps/mobile/components/Modals/AddLink.tsx b/apps/mobile/components/Modals/AddLink.tsx deleted file mode 100644 index c2115fc7..00000000 --- a/apps/mobile/components/Modals/AddLink.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { PropsWithChildren } from "react"; -import { IconSymbol } from "../ui/IconSymbol"; -import ModalBase from "../ModalBase"; -import { Text } from "react-native"; - -type Props = PropsWithChildren<{ - isVisible: boolean; - onClose: () => void; -}>; - -export default function AddLink({ isVisible, onClose }: Props) { - return ( - // - Hi - // - ); -} diff --git a/apps/mobile/eas.json b/apps/mobile/eas.json index c8f1025d..036f2f84 100644 --- a/apps/mobile/eas.json +++ b/apps/mobile/eas.json @@ -20,6 +20,7 @@ } }, "production": { + "corepack": true, "distribution": "store", "autoIncrement": true, "channel": "production" diff --git a/package.json b/package.json index 3fbb67a1..5b500f5c 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,6 @@ "format": "yarn workspaces run format", "postinstall": "yarn workspace @linkwarden/web run postinstall && patch-package" }, - "resolutions": { - "@types/react": "18.3.1", - "@types/react-dom": "18.3.1" - }, "devDependencies": { "dotenv-cli": "^8.0.0" }, From f8efbe95e6350bdc27fc063128a7bdf09971ec97 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sat, 3 Jan 2026 11:07:01 -0500 Subject: [PATCH 3/6] bug fixed --- apps/mobile/app/index.tsx | 96 ++++++++++++++++++++------------------- package.json | 4 ++ 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/apps/mobile/app/index.tsx b/apps/mobile/app/index.tsx index acdd2eee..0a80a483 100644 --- a/apps/mobile/app/index.tsx +++ b/apps/mobile/app/index.tsx @@ -20,56 +20,58 @@ export default function HomeScreen() { return ( - - - - Linkwarden - - - - - Welcome to the official mobile app for Linkwarden! - + + + + + Linkwarden + + + + + Welcome to the official mobile app for Linkwarden! + - - Expect regular improvements and new features as we continue refining - the experience. - + + Expect regular improvements and new features as we continue refining + the experience. + + + + + + + + SheetManager.show("support-sheet")} + > + Need help? + + - - - - - - SheetManager.show("support-sheet")} - > - Need help? - - ); } diff --git a/package.json b/package.json index 5b500f5c..3fbb67a1 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,10 @@ "format": "yarn workspaces run format", "postinstall": "yarn workspace @linkwarden/web run postinstall && patch-package" }, + "resolutions": { + "@types/react": "18.3.1", + "@types/react-dom": "18.3.1" + }, "devDependencies": { "dotenv-cli": "^8.0.0" }, From dd96d80d4230c5c915938cd8163c4029ee3166ca Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sat, 3 Jan 2026 12:24:59 -0500 Subject: [PATCH 4/6] bump version --- apps/mobile/app.json | 2 +- apps/mobile/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/app.json b/apps/mobile/app.json index b4ea6c42..f25ec1cd 100644 --- a/apps/mobile/app.json +++ b/apps/mobile/app.json @@ -2,7 +2,7 @@ "expo": { "name": "Linkwarden", "slug": "linkwarden", - "version": "1.0.0", + "version": "1.0.1", "orientation": "portrait", "icon": "./assets/images/icon.png", "scheme": "linkwarden", diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 3a55e4ed..b35f022b 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -1,7 +1,7 @@ { "name": "@linkwarden/mobile", "main": "expo-router/entry", - "version": "1.0.0", + "version": "1.0.1", "scripts": { "start": "expo start", "android": "expo run:android", From 59252759f24e97674fd0abb176663bc082bce390 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sun, 4 Jan 2026 16:44:17 -0500 Subject: [PATCH 5/6] revert version number to 0.0.0 in package.json (since we're already tracking the version in app.json) --- apps/mobile/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/package.json b/apps/mobile/package.json index b35f022b..20133b9d 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -1,7 +1,7 @@ { "name": "@linkwarden/mobile", "main": "expo-router/entry", - "version": "1.0.1", + "version": "0.0.0", "scripts": { "start": "expo start", "android": "expo run:android", From fdf48abd29e37c56602675ae63f3f8d4f8978294 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Mon, 5 Jan 2026 09:38:33 -0500 Subject: [PATCH 6/6] add pr template --- .github/pull_request_template.md | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..bdbe5864 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,46 @@ +## What does this PR do? + + + +- Fixes #XXXX (GitHub issue number) + +## Visual Demo + +A visual demonstration is strongly recommended, for both the original and new change **(video / image)**. + +#### Video Demo (if applicable): + +- Show screen recordings of the issue or feature. +- Demonstrate how to reproduce the issue, the behavior before and after the change. + +#### Image Demo (if applicable): + +- Add side-by-side screenshots of the original and updated change. +- Highlight any significant change(s). + +## AI Assistance (Required) + +We allow AI-assisted development, but reviewers need transparency to assess risk, maintainability, and correctness. + +#### AI usage level (check one) + +- [ ] None (no AI used) +- [ ] Light (spellcheck/rewording/comments/docs only) +- [ ] Medium (AI suggested small code changes/snippets that I adapted) +- [ ] Heavy (AI significantly shaped the implementation or architecture) + +#### Which tool(s) where used? + +- e.g., ChatGPT, Copilot, Cursor, etc. + +## What was verified by the author? + + + +- [ ] I reviewed **and** understood all AI/human generated code +- [ ] I validated behavior locally (tests/manual verification) +- [ ] I checked edge cases and failure modes + +## Submission Acknowledgement + +- [ ] I acknowledge that a decent size PR without self-review might be rejected