From b5d4d2064f54ab9fa4c34a35d8f5b6c5da460f55 Mon Sep 17 00:00:00 2001 From: Christopher David Date: Fri, 3 Jan 2025 09:45:11 -0600 Subject: [PATCH] Add basic Bitcoin Lightning wallet via Breez SDK (#59) * bump versions to 0.1.0 * npmrc shh * add private spark wallet sdk * initial spark class * singleton * pull in breez service * Enhanced WalletStoreModel with balance tracking and initialization state; added SecureStorageService for improved security. * Refactor WalletStore.ts to use breezService, add TransactionModel, and remove spark dependency. * Refactor WalletStore.ts to remove unused imports and streamline transaction model definitions. * securestorage * shh * breezservice fix type errors * save mnemonic * extract initialize function from walletstore * extract setup * Create file app/models/wallet/actions/types.ts * Refactor `initialize` to use `IWalletStore` interface for better type safety. * extract * Refactor IWalletStore interface: add balance and pending transaction properties, include TransactionModel, and introduce setMnemonic method. * Refactor setup function to use IWalletStore interface for type consistency. * Refactor `restoreWallet` to use `IWalletStore` interface for better type safety and reset balance on wallet restoration. * Added 'types' export and reorganized export order in index.ts for better module structure. * Refactor WalletStore.ts to remove unused imports and streamline the code base. * Refactor `IWalletStore` into `IWalletStoreBase` and `IWalletStore` for clearer separation of base properties and extended functionalities in `types.ts`. * Refactor setup function to use IWalletStoreBase instead of IWalletStore for broader compatibility. * shh * Create file app/models/wallet/actions/fetchBalanceInfo.ts * Create file app/models/wallet/actions/disconnect.ts * Create file app/models/wallet/actions/fetchTransactions.ts * Create file app/models/wallet/actions/sendPayment.ts * Create file app/models/wallet/actions/receivePayment.ts * Add exports for disconnect, balance, transactions, and payment functions to index.ts for expanded module functionality. * Refactor WalletStore.ts: remove unused imports, update properties in WalletStoreModel. * Refactor `types.ts`: Split `IWalletStore` into `IWalletStoreBase` and `IWalletStoreWithTransactions`, add `setError` method, and import `TransactionModel`. * Refactor fetchTransactions to use IWalletStoreWithTransactions for enhanced type safety. * Refactor `sendPayment` to use `IWalletStoreWithTransactions` for enhanced transaction handling. * No changes detected in WalletStore.ts. Commit skipped. * Create file docs/wallet-store.md * Refactor `types.ts`: Replace `IWalletStoreWithTransactions` with `IWalletStoreBalance`, enhancing balance management features. * Refactor fetchBalanceInfo to use IWalletStoreBalance for enhanced type specificity. * Refactor `sendPayment` to improve readability and maintenance by adding explanatory comments. * Refactor WalletStore.ts to organize imports and clean up code structure for better readability. * No changes detected between file revisions. * Added fetchBalanceInfo import in initialize.ts to enhance wallet initialization. * Add `fetchBalanceInfo` import and improve wallet state reset in `restoreWallet` function. * nice * Create file app/models/wallet/views.ts * Add 'views' import to WalletStore.ts to enhance model functionality. * Refactor `views` import to use `createViews` in `WalletStore.ts` for enhanced modularity. * Refactor views.ts to use MST Instance and renamed functions for clarity and type safety. * Create file app/models/wallet/types.ts * Refactor WalletStore.ts by removing unused 'Instance' and 'SnapshotOut' imports to streamline dependencies. * Refactor `views.ts`: Simplify imports, use `WalletStoreType` for type checking, and modify `self` type for clarity and accuracy. * Create file app/types.ts * Refactor `views.ts` to use `WalletStore` from a new path and complete the implementation of `pendingTransactions` view. * Delete app/models/wallet/types.ts * Delete app/models/wallet/actions/types.ts * Create file app/models/wallet/types.ts * Update import path for `WalletStore` in `views.ts` to use local `types` directory. * Delete app/types.ts * testing * Refactor `types.ts`: added `IArrayType` import and replaced `WalletStoreModel` with `TransactionModel` to align with updated data structures. * Add `Instance` import and `IWalletStore` interface to `WalletStore.ts` for enhanced type support. * Refactor fetchTransactions to use IWalletStore and include transaction fee in mapping. * Refactor `restoreWallet`: Add disconnect check for initialized `breezService` before proceeding. * Refactor `IArrayType` to `IAnyModelType` in `types.ts` for broader model compatibility. * Refactor WalletStore.ts: Removed unused 'Instance' import and 'IWalletStore' type, added 'pendingReceiveSat' property to model. * Refactor sendPayment to use IWalletStore and enhance error handling and balance updates. * Refactor WalletStore interfaces in types.ts for clarity and modularization. * Add IWalletStoreProps import to WalletStore.ts for type consistency. * Refactor fetchTransactions to use IWalletStoreProps for enhanced type accuracy. * Refactor `sendPayment` to use `IWalletStoreProps` for enhanced type safety and clarity. * Refactor `IWalletStoreProps` into `IWalletStoreBase` and `IWalletStoreBalance` for clearer separation of concerns. * Refactor WalletStore.ts: Updated import name from IWalletStoreProps to IWalletStore for consistency. * Refactor fetchTransactions to use updated IWalletStore interface for improved type consistency. * Refactor sendPayment to use IWalletStore interface and handle error state by setting it to null. * Refactor `setup.ts` to retrieve mnemonic from secure storage and handle errors, replacing mnemonic generation with error handling. * Refactor fetchBalanceInfo to use updated breezService API and IWalletStore interface for balance details. * Refactor `fetchBalanceInfo` to align property names with `breezService` API changes. * Refactor WalletStore.ts to use destructuring for `Instance` from mobx-state-tree and change `WalletStoreModel` to a non-exported constant. * Updated Wallet Store documentation to clarify the modular architecture and roles of core components. * wallet store hierarchy * nic * initialize * initialize breez sdk store clean * Refactor WalletStore.ts to improve code organization and maintainability. * Refactor fetchTransactions to use setTransactions instead of replace for updating store. * No changes detected in `types.ts`. Commit unnecessary. * fetch balnace info and transactions * Added useNavigation hook to ChatDrawerContent for enhanced navigation handling. * pull in money components etc * initial wallet screen * set isinit * new icon * icons * axe walletsdk for now * Refactor: Import React explicitly in Button.tsx for clarity and consistency. * Refactor Money.tsx by updating enum and type definitions for clarity and consistency. * No changes made to MoneySmall.tsx; verify if commit is necessary. * No changes detected in Money.tsx file; commit unnecessary. * Refactor MoneySmall.tsx: Remove unused imports and optimize component readability. * No changes made to Money.tsx; commit unnecessary. * No changes detected in MoneySmall.tsx. Commit aborted to preserve repository integrity. * No changes detected in Money.tsx. * No changes made to Money.tsx, commit aborted. * Refactor MoneySmall.tsx to remove unused imports and streamline code readability. * No changes detected in Money.tsx file. * No changes detected between the old and new content of MoneySmall.tsx. * Refactor EDenomination enum to type and constant in Money.tsx for improved type safety and flexibility. * denom types * ok * derive nostr keys and save to walletstore * show npub * Added StyleSheet import to ChatDrawerContent for custom styling. * disable send/receive for now * nice * Create file app/chat/drawer/styles.ts * Create file app/chat/drawer/ChatPreview.ts * Create file app/chat/drawer/NewChatButton.tsx * Create file app/chat/drawer/WalletButton.tsx * Create file app/chat/drawer/ChatList.tsx * Create file app/chat/drawer/index.tsx * Delete app/chat/ChatDrawerContent.tsx * Create file app/chat/drawer/ChatDrawerLayout.tsx * Delete app/chat/ChatDrawerContainer.tsx * Refactor `ChatDrawerContent` to use proper typing for `drawerInsets` in `index.tsx`. * chatdrawerlayout * border button * Create file app/chat/drawer/README.md * yarn hierarchy * Create file app/screens/ProfileScreen/ProfileScreen.tsx * Create file app/screens/ProfileScreen/index.ts * Added export for ProfileScreen in index.ts to facilitate module access. * Refactor AppNavigator.tsx to remove unused imports and streamline navigation setup. * Create file app/chat/drawer/ProfileButton.tsx * Add ProfileButton to ChatDrawerContent and update imports in index.tsx. * Refactor WalletButton to use functional component structure for clarity and maintenance. * button * Refactor ProfileButton.tsx to use local styles and MaterialCommunityIcons, improving UI consistency and performance. * onyx profile * shh * hm * Add useState, Pressable, Clipboard, and MaterialCommunityIcons to ProfileScreen; introduce KeyRow component for handling secret keys. * Refactor ProfileScreen: Replace Pressable with TouchableOpacity, update Clipboard import for better modularity. * cool * Create file app/screens/ProfileScreen/KeyRow.tsx * Refactor ProfileScreen.tsx: Removed unused imports, extracted KeyRow component, and integrated useStores for state management. * copied * profilebutton * Create file docs/pro.md * Add authentication section requiring Nostr public key for API requests in `pro.md`. * Create file app/services/aiur/aiur.types.ts * Create file app/services/aiur/aiur.ts * Create file app/services/aiur/index.ts * Create file docs/aiur.md * Updated aiur.md to clarify Aiur's role and its decentralized services. * Add fallback URL to DEFAULT_AIUR_CONFIG in aiur.ts for increased reliability. * Add AIUR_API_URL to ConfigBaseProps and remove GROQ_API_KEY. * Added AIUR_API_URL to config.dev.ts for local AI service integration. * Added AIUR_API_URL to production config for new service integration. * Update DEFAULT_AIUR_CONFIG URL to use localhost in dev environments for Aiur API. * hierarchy * shh * Create file app/navigators/SettingsNavigator.tsx * Create file app/screens/SettingsScreen/AutocoderSettings.tsx * Enhance SettingsScreen with sharing feature, navigation updates, and style adjustments. * Add SettingsNavigator import to AppNavigator for enhanced settings navigation. * Delete app/screens/SettingsScreen/coder/RepoSettings.tsx * Create file app/screens/SettingsScreen/styles.ts * Refactor SettingsScreen to use local styles import. * Refactor styles.ts to include typography, update button and container styles, and adjust color scheme for improved UI consistency. * Refactor SettingsScreen: remove unused 'colors' import and update share message. * Create file app/screens/ShareScreen/ShareScreen.tsx * Added ShareScreen to SettingsNavigator and updated SettingsStackParamList. * Refactor SettingsScreen: remove unused Share import and update UI to navigate to ShareScreen on button press. * padding * Added Ionicons and colorsDark to SettingsScreen for enhanced UI elements. * Refactor ShareScreen to use MobX, add KeyboardAvoidingView, ScrollView, and Button components for enhanced functionality and interactivity. * hierarchy * Add TextInput import and extend styles in ShareScreen.tsx for enhanced text input functionality. * Refactor ShareRequest and Share interfaces to include messages and metadata, replacing previous fields to support enhanced sharing features. * Refactor ShareScreen.tsx to improve readability and maintainability. * Refactor AiurApi class to improve code organization and readability. * hm * nice * red * sharescreen * android fix fonts * Create file scripts/deepseek_test_fixer.sh * pull in wallet screens * tsc 8 * hm * update hierarchy * Refactor: Cleaned up imports and removed unused `useNavigation` in `BackupWalletScreen.tsx`. * Add TextStyle import in ReceiveScreen.tsx for enhanced styling options. * Refactor WalletStore.ts to streamline imports and remove unused variables for improved clarity and maintainability. * Added TextStyle import to RestoreWalletScreen for enhanced text styling. * Refactor AppNavigator.tsx to use relative imports for better maintainability and consistency. * Refactor WalletScreen.tsx: Remove unused imports and useEffect, streamline component. * Create file app/navigators/WalletNavigator.tsx * Refactor AppNavigator.tsx to improve import efficiency by consolidating navigation utilities. * Refactor WalletScreen to use typed navigation props from WalletNavigator. * Refactor SendScreen to use NativeStackScreenProps and simplify imports and components. * Refactor ReceiveScreen to use NativeStackScreenProps for improved type safety and navigation consistency. * Refactor BackupWalletScreen to use NativeStackScreenProps for navigation type safety. * Refactor RestoreWalletScreen to use NativeStackScreenProps for improved type safety and navigation handling. * Refactor SendScreen.tsx to include useState, additional imports, and useStores hook for enhanced functionality. * Refactor RestoreWalletScreen to improve readability and maintenance by reorganizing imports and interfaces. * No changes detected in BackupWalletScreen.tsx. * Refactor ReceiveScreen.tsx for code clarity and maintainability. * sendreceive nav * backup wallet * backuprestore * cool * Refactor BackupWalletScreen to improve code readability and maintainability. * Create file app/services/notifications/index.ts * No changes detected in app.tsx; commit unnecessary. * No changes detected between old and new content of app.config.ts. * Create file app/hooks/useNotifications.ts * npx expo install expo-notifications expo-device expo-constants * axe gemini key shaz * No changes detected; commit skipped. * No changes detected in app.config.ts; commit unnecessary. * Added `sendPushNotification` function to handle sending push notifications in `index.ts`. * Refactor useNotifications hook to manage state with useState and update listener types for improved handling of Expo notifications. * hierarchy * Create file app/screens/SettingsScreen/NotificationsScreen.tsx * Added NotificationsScreen to SettingsNavigator and updated SettingsStackParamList. * Refactored SettingsScreen to enhance readability and maintainability. * ok * hierarchy * Create file app/models/user/UserStore.ts * Added UserStoreModel to RootStore for enhanced user management. * Added useStores import to NotificationsScreen for state management integration. * Added KeyRow import to NotificationsScreen for enhanced user settings management. * invoice only --------- Co-authored-by: GitHub API --- .gitignore | 2 + app.config.ts | 3 +- app.json | 4 +- app/app.tsx | 8 +- app/chat/ChatDrawerContent.tsx | 127 -------- .../ChatDrawerLayout.tsx} | 12 +- app/chat/drawer/ChatList.tsx | 43 +++ app/chat/drawer/ChatPreview.ts | 22 ++ app/chat/drawer/NewChatButton.tsx | 26 ++ app/chat/drawer/ProfileButton.tsx | 33 +++ app/chat/drawer/README.md | 117 ++++++++ app/chat/drawer/WalletButton.tsx | 28 ++ app/chat/drawer/index.tsx | 39 +++ app/chat/drawer/styles.ts | 59 ++++ app/chat/markdown/ToolInvocation.tsx | 2 - app/components/Button.tsx | 246 ++++++++++++++++ app/components/Icon.tsx | 34 ++- app/components/index.ts | 4 + app/config/config.base.ts | 24 +- app/config/config.dev.ts | 1 + app/config/config.prod.ts | 1 + app/hooks/useNotifications.ts | 52 ++++ app/models/RootStore.ts | 12 +- app/models/_helpers/useStores.ts | 5 +- app/models/user/UserStore.ts | 40 +++ app/models/wallet/WalletStore.ts | 74 +++++ app/models/wallet/actions/disconnect.ts | 18 ++ app/models/wallet/actions/fetchBalanceInfo.ts | 19 ++ .../wallet/actions/fetchTransactions.ts | 22 ++ app/models/wallet/actions/index.ts | 7 + app/models/wallet/actions/receivePayment.ts | 18 ++ app/models/wallet/actions/restoreWallet.ts | 56 ++++ app/models/wallet/actions/sendPayment.ts | 21 ++ app/models/wallet/actions/setup.ts | 54 ++++ app/models/wallet/models.ts | 19 ++ app/models/wallet/types.ts | 45 +++ app/models/wallet/views.ts | 16 + app/navigators/AppNavigator.tsx | 28 +- app/navigators/SettingsNavigator.tsx | 30 ++ app/navigators/WalletNavigator.tsx | 33 +++ app/screens/ChatScreen/ChatScreen.tsx | 4 +- app/screens/ErrorScreen/ErrorDetails.tsx | 37 +-- app/screens/ProfileScreen/KeyRow.tsx | 102 +++++++ app/screens/ProfileScreen/ProfileScreen.tsx | 67 +++++ app/screens/ProfileScreen/index.ts | 1 + ...RepoSettings.tsx => AutocoderSettings.tsx} | 23 +- .../SettingsScreen/NotificationsScreen.tsx | 101 +++++++ app/screens/SettingsScreen/SettingsScreen.tsx | 36 ++- app/screens/SettingsScreen/coder/styles.ts | 8 +- app/screens/SettingsScreen/coder/types.ts | 5 - app/screens/SettingsScreen/styles.ts | 40 +++ app/screens/ShareScreen/ShareScreen.tsx | 168 +++++++++++ .../WalletScreen/BackupWalletScreen.tsx | 65 +++++ app/screens/WalletScreen/BalanceHeader.tsx | 103 +++++++ app/screens/WalletScreen/Money.tsx | 173 +++++++++++ app/screens/WalletScreen/MoneySmall.tsx | 204 +++++++++++++ app/screens/WalletScreen/ReceiveScreen.tsx | 258 +++++++++++++++++ .../WalletScreen/RestoreWalletScreen.tsx | 133 +++++++++ app/screens/WalletScreen/SendScreen.tsx | 179 ++++++++++++ app/screens/WalletScreen/TransactionsList.tsx | 131 +++++++++ app/screens/WalletScreen/WalletScreen.tsx | 96 ++++++ app/screens/WalletScreen/index.ts | 5 + app/screens/index.ts | 2 + app/services/aiur/aiur.ts | 139 +++++++++ app/services/aiur/aiur.types.ts | 54 ++++ app/services/aiur/index.ts | 2 + app/services/breez/breezService.ts | 274 ++++++++++++++++++ app/services/breez/index.ts | 2 + app/services/breez/types.ts | 34 +++ app/services/nostr/nostr.ts | 41 +++ app/services/nostr/nostr.types.ts | 6 + app/services/notifications/index.ts | 138 +++++++++ app/services/storage/secureStorage.ts | 42 +++ app/theme/colorsDark.ts | 2 +- app/theme/onyx.ts | 1 + app/theme/typography.ts | 1 + app/utils/alert.ts | 57 ++++ assets/images/app-icon-all.png | Bin 81725 -> 157881 bytes assets/images/app-icon-old.png | Bin 0 -> 81725 bytes assets/images/splash-old.png | Bin 0 -> 66787 bytes assets/images/splash.png | Bin 66787 -> 16538 bytes docs/aiur.md | 101 +++++++ docs/hierarchy.md | 71 ++++- docs/pro.md | 139 +++++++++ docs/wallet-store.md | 155 ++++++++++ eas.json | 4 +- package.json | 16 +- scripts/deepseek_test_fixer.sh | 98 +++++++ yarn.lock | 199 ++++++++++++- 89 files changed, 4647 insertions(+), 274 deletions(-) delete mode 100644 app/chat/ChatDrawerContent.tsx rename app/chat/{ChatDrawerContainer.tsx => drawer/ChatDrawerLayout.tsx} (74%) create mode 100644 app/chat/drawer/ChatList.tsx create mode 100644 app/chat/drawer/ChatPreview.ts create mode 100644 app/chat/drawer/NewChatButton.tsx create mode 100644 app/chat/drawer/ProfileButton.tsx create mode 100644 app/chat/drawer/README.md create mode 100644 app/chat/drawer/WalletButton.tsx create mode 100644 app/chat/drawer/index.tsx create mode 100644 app/chat/drawer/styles.ts create mode 100644 app/components/Button.tsx create mode 100644 app/hooks/useNotifications.ts create mode 100644 app/models/user/UserStore.ts create mode 100644 app/models/wallet/WalletStore.ts create mode 100644 app/models/wallet/actions/disconnect.ts create mode 100644 app/models/wallet/actions/fetchBalanceInfo.ts create mode 100644 app/models/wallet/actions/fetchTransactions.ts create mode 100644 app/models/wallet/actions/index.ts create mode 100644 app/models/wallet/actions/receivePayment.ts create mode 100644 app/models/wallet/actions/restoreWallet.ts create mode 100644 app/models/wallet/actions/sendPayment.ts create mode 100644 app/models/wallet/actions/setup.ts create mode 100644 app/models/wallet/models.ts create mode 100644 app/models/wallet/types.ts create mode 100644 app/models/wallet/views.ts create mode 100644 app/navigators/SettingsNavigator.tsx create mode 100644 app/navigators/WalletNavigator.tsx create mode 100644 app/screens/ProfileScreen/KeyRow.tsx create mode 100644 app/screens/ProfileScreen/ProfileScreen.tsx create mode 100644 app/screens/ProfileScreen/index.ts rename app/screens/SettingsScreen/{coder/RepoSettings.tsx => AutocoderSettings.tsx} (85%) create mode 100644 app/screens/SettingsScreen/NotificationsScreen.tsx create mode 100644 app/screens/SettingsScreen/styles.ts create mode 100644 app/screens/ShareScreen/ShareScreen.tsx create mode 100644 app/screens/WalletScreen/BackupWalletScreen.tsx create mode 100644 app/screens/WalletScreen/BalanceHeader.tsx create mode 100644 app/screens/WalletScreen/Money.tsx create mode 100644 app/screens/WalletScreen/MoneySmall.tsx create mode 100644 app/screens/WalletScreen/ReceiveScreen.tsx create mode 100644 app/screens/WalletScreen/RestoreWalletScreen.tsx create mode 100644 app/screens/WalletScreen/SendScreen.tsx create mode 100644 app/screens/WalletScreen/TransactionsList.tsx create mode 100644 app/screens/WalletScreen/WalletScreen.tsx create mode 100644 app/screens/WalletScreen/index.ts create mode 100644 app/services/aiur/aiur.ts create mode 100644 app/services/aiur/aiur.types.ts create mode 100644 app/services/aiur/index.ts create mode 100644 app/services/breez/breezService.ts create mode 100644 app/services/breez/index.ts create mode 100644 app/services/breez/types.ts create mode 100644 app/services/nostr/nostr.ts create mode 100644 app/services/nostr/nostr.types.ts create mode 100644 app/services/notifications/index.ts create mode 100644 app/services/storage/secureStorage.ts create mode 100644 app/utils/alert.ts create mode 100644 assets/images/app-icon-old.png create mode 100644 assets/images/splash-old.png create mode 100644 docs/aiur.md create mode 100644 docs/pro.md create mode 100644 docs/wallet-store.md create mode 100644 scripts/deepseek_test_fixer.sh diff --git a/.gitignore b/.gitignore index 115624eb..57fd0dd7 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,5 @@ web-build/ .env .env.local + +.npmrc diff --git a/app.config.ts b/app.config.ts index 20ffbb80..27d605ac 100644 --- a/app.config.ts +++ b/app.config.ts @@ -21,6 +21,7 @@ module.exports = ({ config }: ConfigContext): Partial => { ...existingPlugins, 'expo-localization', 'expo-sqlite', + 'expo-notifications', ], extra: { ...config.extra, @@ -29,4 +30,4 @@ module.exports = ({ config }: ConfigContext): Partial => { GROQ_API_KEY: process.env.GROQ_API_KEY, }, } -} +} \ No newline at end of file diff --git a/app.json b/app.json index 7483c610..7062bffc 100644 --- a/app.json +++ b/app.json @@ -3,7 +3,7 @@ "name": "Onyx", "slug": "onyx", "scheme": "onyx", - "version": "0.0.6", + "version": "0.1.0", "orientation": "portrait", "userInterfaceStyle": "automatic", "icon": "./assets/images/app-icon-all.png", @@ -73,7 +73,7 @@ "expo-splash-screen", { "image": "./assets/images/splash.png", - "resizeMode": "cover", + "resizeMode": "contain", "backgroundColor": "#000000" } ] diff --git a/app/app.tsx b/app/app.tsx index 018b7ed1..f9d5d5ed 100644 --- a/app/app.tsx +++ b/app/app.tsx @@ -17,6 +17,7 @@ import { useInitialRootStore } from "./models" import { AppNavigator, useNavigationPersistence } from "./navigators" import { ErrorBoundary } from "./screens/ErrorScreen/ErrorBoundary" import * as storage from "./utils/storage" +import NotificationService from "./services/notifications" interface AppProps { hideSplashScreen: () => Promise @@ -38,6 +39,11 @@ function App(props: AppProps) { setTimeout(hideSplashScreen, 500) }) + // Initialize notifications + React.useEffect(() => { + NotificationService.init().catch(console.error) + }, []) + if (!loaded || !rehydrated || !isNavigationStateRestored) { return ( @@ -62,4 +68,4 @@ function App(props: AppProps) { AppRegistry.registerComponent("main", () => App) -export default App +export default App \ No newline at end of file diff --git a/app/chat/ChatDrawerContent.tsx b/app/chat/ChatDrawerContent.tsx deleted file mode 100644 index f95507bc..00000000 --- a/app/chat/ChatDrawerContent.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { observer } from "mobx-react-lite" -import { useEffect } from "react" -import { ScrollView, Text, TouchableOpacity, View } from "react-native" -import { useStores } from "@/models" -import { colorsDark as colors, typography } from "@/theme" -import { MaterialCommunityIcons } from "@expo/vector-icons" - -type Props = { - drawerInsets: any // replace any with the correct type - setOpen: (open: boolean) => void -} - -export const ChatDrawerContent = observer(({ drawerInsets, setOpen }: Props) => { - const { chatStore } = useStores() - - useEffect(() => { - chatStore.loadAllChats() - }, []) - - const handleNewChat = () => { - // Generate a new conversation ID - const newId = `chat_${Date.now()}` - chatStore.setCurrentConversationId(newId) - chatStore.clearMessages() - setOpen(false) // Close the drawer after creating new chat - } - - const handleSelectChat = (chatId: string) => { - chatStore.setCurrentConversationId(chatId) - setOpen(false) - } - - const getChatPreview = (messages: any[]) => { - if (!messages || messages.length === 0) { - return "New Chat" - } - const lastUserMessage = messages.filter((msg) => msg.role === "user").pop() - if (!lastUserMessage) { - return "New Chat" - } - const preview = lastUserMessage.content.trim() - if (preview.length <= 30) { - return preview - } - return preview.slice(0, 30) + "..." - } - - // Sort chats by creation time (using first message's timestamp or chat ID timestamp) - const sortedChats = [...chatStore.allChats].sort((a, b) => { - const aTime = a.messages[0]?.createdAt || parseInt(a.id.split("_")[1]) || 0 - const bTime = b.messages[0]?.createdAt || parseInt(b.id.split("_")[1]) || 0 - return bTime - aTime // Reverse chronological order - }) - - return ( - - - - - - New chat - - - - - - {sortedChats.map((chat) => ( - handleSelectChat(chat.id)} - style={{ - padding: 16, - borderBottomWidth: 1, - borderBottomColor: colors.border, - backgroundColor: - chatStore.currentConversationId === chat.id - ? colors.palette.neutral200 - : "transparent", - }} - > - - {getChatPreview(chat.messages)} - - - {new Date( - chat.messages[0]?.createdAt || parseInt(chat.id.split("_")[1]) || Date.now(), - ).toLocaleDateString()} - - - ))} - - - ) -}) diff --git a/app/chat/ChatDrawerContainer.tsx b/app/chat/drawer/ChatDrawerLayout.tsx similarity index 74% rename from app/chat/ChatDrawerContainer.tsx rename to app/chat/drawer/ChatDrawerLayout.tsx index ec3af091..a3109cb5 100644 --- a/app/chat/ChatDrawerContainer.tsx +++ b/app/chat/drawer/ChatDrawerLayout.tsx @@ -1,15 +1,14 @@ import { useState } from "react" -import { Platform } from "react-native" import { Drawer } from "react-native-drawer-layout" import { Screen } from "@/components/Screen" import { $styles } from "@/theme" import { useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle" -import { Chat } from "./Chat" -import { ChatDrawerContent } from "./ChatDrawerContent" +import { Chat } from "../Chat" +import { ChatDrawerContent } from "./index" -export const ChatDrawerContainer = () => { +export const ChatDrawerLayout = () => { const [open, setOpen] = useState(false) - const $drawerInsets = useSafeAreaInsetsStyle(["top"]) + const $drawerInsets = useSafeAreaInsetsStyle(["top", "bottom"]) return ( { > @@ -31,4 +29,4 @@ export const ChatDrawerContainer = () => { ) -} +} \ No newline at end of file diff --git a/app/chat/drawer/ChatList.tsx b/app/chat/drawer/ChatList.tsx new file mode 100644 index 00000000..379a0ccd --- /dev/null +++ b/app/chat/drawer/ChatList.tsx @@ -0,0 +1,43 @@ +import { ScrollView, TouchableOpacity, Text } from "react-native" +import { useStores } from "@/models" +import { styles } from "./styles" +import { getChatPreview, sortChats } from "./ChatPreview" + +type Props = { + setOpen: (open: boolean) => void +} + +export const ChatList = ({ setOpen }: Props) => { + const { chatStore } = useStores() + + const handleSelectChat = (chatId: string) => { + chatStore.setCurrentConversationId(chatId) + setOpen(false) + } + + const sortedChats = sortChats(chatStore.allChats) + + return ( + + {sortedChats.map((chat) => ( + handleSelectChat(chat.id)} + style={[ + styles.chatItem, + chatStore.currentConversationId === chat.id && styles.selectedChat, + ]} + > + + {getChatPreview(chat.messages)} + + + {new Date( + chat.messages[0]?.createdAt || parseInt(chat.id.split("_")[1]) || Date.now(), + ).toLocaleDateString()} + + + ))} + + ) +} \ No newline at end of file diff --git a/app/chat/drawer/ChatPreview.ts b/app/chat/drawer/ChatPreview.ts new file mode 100644 index 00000000..55b8e613 --- /dev/null +++ b/app/chat/drawer/ChatPreview.ts @@ -0,0 +1,22 @@ +export const getChatPreview = (messages: any[]) => { + if (!messages || messages.length === 0) { + return "New Chat" + } + const lastUserMessage = messages.filter((msg) => msg.role === "user").pop() + if (!lastUserMessage) { + return "New Chat" + } + const preview = lastUserMessage.content.trim() + if (preview.length <= 30) { + return preview + } + return preview.slice(0, 30) + "..." +} + +export const sortChats = (chats: any[]) => { + return [...chats].sort((a, b) => { + const aTime = a.messages[0]?.createdAt || parseInt(a.id.split("_")[1]) || 0 + const bTime = b.messages[0]?.createdAt || parseInt(b.id.split("_")[1]) || 0 + return bTime - aTime // Reverse chronological order + }) +} \ No newline at end of file diff --git a/app/chat/drawer/NewChatButton.tsx b/app/chat/drawer/NewChatButton.tsx new file mode 100644 index 00000000..751867b0 --- /dev/null +++ b/app/chat/drawer/NewChatButton.tsx @@ -0,0 +1,26 @@ +import { TouchableOpacity, Text } from "react-native" +import { MaterialCommunityIcons } from "@expo/vector-icons" +import { useStores } from "@/models" +import { styles } from "./styles" + +type Props = { + setOpen: (open: boolean) => void +} + +export const NewChatButton = ({ setOpen }: Props) => { + const { chatStore } = useStores() + + const handleNewChat = () => { + const newId = `chat_${Date.now()}` + chatStore.setCurrentConversationId(newId) + chatStore.clearMessages() + setOpen(false) + } + + return ( + + + New chat + + ) +} \ No newline at end of file diff --git a/app/chat/drawer/ProfileButton.tsx b/app/chat/drawer/ProfileButton.tsx new file mode 100644 index 00000000..2e04ddea --- /dev/null +++ b/app/chat/drawer/ProfileButton.tsx @@ -0,0 +1,33 @@ +import { observer } from "mobx-react-lite" +import React from "react" +import { Text, TouchableOpacity } from "react-native" +import { useStores } from "@/models" +import { navigate } from "@/navigators" +import { MaterialCommunityIcons } from "@expo/vector-icons" +import { styles } from "./styles" + +interface ProfileButtonProps { + setOpen: (open: boolean) => void +} + +export const ProfileButton = observer(({ setOpen }: ProfileButtonProps) => { + const { walletStore } = useStores() + const npub = walletStore.nostrKeys?.npub + + const handleProfilePress = () => { + setOpen(false) + navigate("Profile") + } + + return ( + + + + Profile ({npub ? npub.slice(0, 8) + "..." : "Not connected"}) + + + ) +}) diff --git a/app/chat/drawer/README.md b/app/chat/drawer/README.md new file mode 100644 index 00000000..d23fe268 --- /dev/null +++ b/app/chat/drawer/README.md @@ -0,0 +1,117 @@ +# Chat Drawer Components + +This directory contains the components and utilities for the chat drawer functionality in the Onyx app. + +## Directory Structure + +``` +app/chat/drawer/ +├── ChatDrawerLayout.tsx # Main layout wrapper component +├── ChatList.tsx # Chat history list component +├── ChatPreview.ts # Chat preview utilities +├── NewChatButton.tsx # New chat button component +├── WalletButton.tsx # Wallet button component +├── index.tsx # Main exports and drawer content +├── styles.ts # Shared styles +└── README.md # This file +``` + +## Component Overview + +### ChatDrawerLayout.tsx +- Main container that manages the drawer state and layout +- Wraps both the drawer content and main chat interface +- Uses react-native-drawer-layout for drawer functionality +- Props: None (self-contained with internal state) + +### ChatList.tsx +- Displays the list of chat history +- Handles chat selection +- Props: + - `setOpen: (open: boolean) => void` - Function to control drawer state + +### ChatPreview.ts +Utility functions for chat management: +- `getChatPreview(messages: any[])` - Generates preview text from chat messages +- `sortChats(chats: any[])` - Sorts chats by creation time + +### NewChatButton.tsx +- Button component for creating new chats +- Handles chat creation logic +- Props: + - `setOpen: (open: boolean) => void` - Function to control drawer state + +### WalletButton.tsx +- Button component for wallet functionality +- Displays wallet balance and navigation +- Props: + - `setOpen: (open: boolean) => void` - Function to control drawer state + +### index.tsx +- Main entry point for drawer components +- Exports ChatDrawerContent and ChatDrawerLayout +- ChatDrawerContent Props: + - `drawerInsets: any` - Safe area insets for proper layout + - `setOpen: (open: boolean) => void` - Drawer state control + +### styles.ts +- Centralized styles for all drawer components +- Uses theme colors and typography from @/theme + +## Making Changes + +### Adding New Features +1. For new UI elements: + - Create a new component file in this directory + - Add styles to styles.ts + - Export the component in index.tsx if needed externally + +2. For new functionality: + - Add utility functions to appropriate files or create new ones + - Update types as needed + - Consider impacts on state management in ChatDrawerLayout + +### Modifying Existing Features +1. Styles: + - All styles are in styles.ts + - Follow existing pattern for consistency + - Use theme variables from @/theme + +2. Chat List: + - Chat preview logic is in ChatPreview.ts + - Sort/filter logic should go there as well + +3. State Management: + - Drawer open/close state is managed in ChatDrawerLayout + - Chat state is managed through chatStore (from @/models) + +### Best Practices +- Keep components focused and single-responsibility +- Use consistent prop naming (e.g., setOpen for drawer control) +- Maintain type safety (avoid 'any' where possible) +- Follow existing patterns for styling and state management +- Add comments for complex logic +- Update this README when adding new components or changing architecture + +## Common Tasks + +### Adding a New Button +1. Create new component file (e.g., MyButton.tsx) +2. Add styles to styles.ts +3. Add component to ChatDrawerContent in index.tsx + +### Modifying Chat Preview +1. Update logic in ChatPreview.ts +2. Test with different message formats +3. Update ChatList.tsx if display changes needed + +### Adding New State +1. Consider whether it belongs in chatStore or local state +2. If local, add to relevant component +3. If global, add to chatStore in @/models + +## Dependencies +- react-native-drawer-layout +- mobx-react-lite (for state management) +- @/models (for chat and wallet stores) +- @/theme (for styling) \ No newline at end of file diff --git a/app/chat/drawer/WalletButton.tsx b/app/chat/drawer/WalletButton.tsx new file mode 100644 index 00000000..926336f3 --- /dev/null +++ b/app/chat/drawer/WalletButton.tsx @@ -0,0 +1,28 @@ +import { TouchableOpacity, Text } from "react-native" +import { MaterialCommunityIcons } from "@expo/vector-icons" +import { useNavigation } from "@react-navigation/native" +import { useStores } from "@/models" +import { styles } from "./styles" + +type Props = { + setOpen: (open: boolean) => void +} + +export const WalletButton = ({ setOpen }: Props) => { + const navigation = useNavigation() + const { walletStore } = useStores() + + const handleWalletPress = () => { + navigation.navigate("Wallet" as never) + setOpen(false) + } + + return ( + + + + Wallet (₿{walletStore.balanceSat}) + + + ) +} \ No newline at end of file diff --git a/app/chat/drawer/index.tsx b/app/chat/drawer/index.tsx new file mode 100644 index 00000000..79e0c33b --- /dev/null +++ b/app/chat/drawer/index.tsx @@ -0,0 +1,39 @@ +import { observer } from "mobx-react-lite" +import { useEffect } from "react" +import { View } from "react-native" +import { useStores } from "@/models" +import { styles } from "./styles" +import { NewChatButton } from "./NewChatButton" +import { ChatList } from "./ChatList" +import { WalletButton } from "./WalletButton" +import { ProfileButton } from "./ProfileButton" + +type Props = { + drawerInsets: any // replace any with the correct type + setOpen: (open: boolean) => void +} + +export const ChatDrawerContent = observer(({ drawerInsets, setOpen }: Props) => { + const { chatStore } = useStores() + + useEffect(() => { + chatStore.loadAllChats() + }, []) + + return ( + + + + + + + + + + + + + ) +}) + +export { ChatDrawerLayout } from "./ChatDrawerLayout" \ No newline at end of file diff --git a/app/chat/drawer/styles.ts b/app/chat/drawer/styles.ts new file mode 100644 index 00000000..6ccbb96e --- /dev/null +++ b/app/chat/drawer/styles.ts @@ -0,0 +1,59 @@ +import { StyleSheet } from "react-native" +import { colorsDark as colors, typography } from "@/theme" + +export const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "black", + borderRightWidth: 1, + borderRightColor: colors.border, + }, + topSection: { + paddingHorizontal: 20, + paddingVertical: 10, + borderBottomWidth: 1, + borderBottomColor: colors.border, + }, + bottomSection: { + paddingHorizontal: 20, + paddingVertical: 10, + borderTopWidth: 1, + borderTopColor: colors.border, + }, + newChatButton: { + flexDirection: "row", + alignItems: "center", + marginBottom: 8, + }, + walletButton: { + flexDirection: "row", + alignItems: "center", + }, + buttonText: { + fontFamily: typography.primary.medium, + color: "white", + marginLeft: 12, + }, + scrollView: { + flex: 1, + }, + chatItem: { + paddingHorizontal: 12, + paddingVertical: 8, + borderBottomWidth: 1, + borderBottomColor: colors.border, + backgroundColor: "transparent", + }, + selectedChat: { + backgroundColor: colors.palette.neutral200, + }, + chatPreviewText: { + color: "white", + fontFamily: typography.primary.medium, + marginBottom: 4, + }, + dateText: { + color: colors.palette.neutral400, + fontSize: 12, + }, +}) diff --git a/app/chat/markdown/ToolInvocation.tsx b/app/chat/markdown/ToolInvocation.tsx index e5c51917..e462eb20 100644 --- a/app/chat/markdown/ToolInvocation.tsx +++ b/app/chat/markdown/ToolInvocation.tsx @@ -175,7 +175,6 @@ const styles = StyleSheet.create({ }, title: { fontSize: 14, - fontWeight: "bold", fontFamily: typography.primary.bold, color: colors.text, marginRight: 8, @@ -231,7 +230,6 @@ const styles = StyleSheet.create({ }, modalTitle: { fontSize: 18, - fontWeight: "bold", fontFamily: typography.primary.normal, color: colors.text, marginBottom: 4, diff --git a/app/components/Button.tsx b/app/components/Button.tsx new file mode 100644 index 00000000..3b8ac2c0 --- /dev/null +++ b/app/components/Button.tsx @@ -0,0 +1,246 @@ +import React, { ComponentType } from "react" +import { + Pressable, + PressableProps, + PressableStateCallbackType, + StyleProp, + TextStyle, + ViewStyle, +} from "react-native" +import { useAppTheme } from "@/utils/useAppTheme" +import { $styles } from "../theme" +import { Text, TextProps } from "./Text" + +import type { ThemedStyle, ThemedStyleArray } from "@/theme" +type Presets = "default" | "filled" | "reversed" + +export interface ButtonAccessoryProps { + style: StyleProp + pressableState: PressableStateCallbackType + disabled?: boolean +} + +export interface ButtonProps extends PressableProps { + /** + * Text which is looked up via i18n. + */ + tx?: TextProps["tx"] + /** + * The text to display if not using `tx` or nested components. + */ + text?: TextProps["text"] + /** + * Optional options to pass to i18n. Useful for interpolation + * as well as explicitly setting locale or translation fallbacks. + */ + txOptions?: TextProps["txOptions"] + /** + * An optional style override useful for padding & margin. + */ + style?: StyleProp + /** + * An optional style override for the "pressed" state. + */ + pressedStyle?: StyleProp + /** + * An optional style override for the button text. + */ + textStyle?: StyleProp + /** + * An optional style override for the button text when in the "pressed" state. + */ + pressedTextStyle?: StyleProp + /** + * An optional style override for the button text when in the "disabled" state. + */ + disabledTextStyle?: StyleProp + /** + * One of the different types of button presets. + */ + preset?: Presets + /** + * An optional component to render on the right side of the text. + * Example: `RightAccessory={(props) => }` + */ + RightAccessory?: ComponentType + /** + * An optional component to render on the left side of the text. + * Example: `LeftAccessory={(props) => }` + */ + LeftAccessory?: ComponentType + /** + * Children components. + */ + children?: React.ReactNode + /** + * disabled prop, accessed directly for declarative styling reasons. + * https://reactnative.dev/docs/pressable#disabled + */ + disabled?: boolean + /** + * An optional style override for the disabled state + */ + disabledStyle?: StyleProp +} + +/** + * A component that allows users to take actions and make choices. + * Wraps the Text component with a Pressable component. + * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Button/} + * @param {ButtonProps} props - The props for the `Button` component. + * @returns {JSX.Element} The rendered `Button` component. + * @example + *