mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
This pull request introduces several improvements and refactors to the iOS frontend, with a focus on the paywall system, configuration, and developer experience. The most significant changes include dynamic pricing updates for subscription packages, the introduction of a centralized pricing configuration, and enhanced developer documentation and settings for Claude Code. There are also minor fixes and improvements to restore purchase flows, App Store syncing, and protocol usage guidance. **Paywall System Improvements** * Subscription package pricing and display is now dynamically updated based on App Store data, ensuring users see accurate, localized pricing and descriptions. This includes new logic for calculating monthly prices and updating package button text. (`ViewModel.swift`, `ViewModel+Action.swift`, `SKUnit+Pro.swift`, `SKUnit+AI.swift`) [[1]](diffhunk://#diff-cb192a424400265435cb06d86b204aa17b4e8195d9dd811580f51faeda211ff0R83-R160) [[2]](diffhunk://#diff-cb192a424400265435cb06d86b204aa17b4e8195d9dd811580f51faeda211ff0L102-R199) [[3]](diffhunk://#diff-df2cb61867b4ff10dee98d534cf3c94fe8d48ebaef3f219450a9fba26725fdcbL58-R73) [[4]](diffhunk://#diff-df2cb61867b4ff10dee98d534cf3c94fe8d48ebaef3f219450a9fba26725fdcbL74-R94) [[5]](diffhunk://#diff-ea535c02550f727587e74521da8fd90dec23cbe3c685f9c4aa4923ce0bbdb363L19-R35) [[6]](diffhunk://#diff-a5fef660f959bbb52ce3f19bba8bfbd0bb00d66c9f18a20a998101b5df6c8f60L18-R22) * Introduced a new `PricingConfiguration.swift` file to centralize product identifiers, default selections, and display strings for subscription products, improving maintainability and consistency. (`PricingConfiguration.swift`, `SKUnit+Pro.swift`, `SKUnit+AI.swift`) [[1]](diffhunk://#diff-de4566ecd5bd29f36737ae5e5904345bd1a5c8f0a73140c3ebba41856bae3e86R1-R54) [[2]](diffhunk://#diff-ea535c02550f727587e74521da8fd90dec23cbe3c685f9c4aa4923ce0bbdb363L19-R35) [[3]](diffhunk://#diff-a5fef660f959bbb52ce3f19bba8bfbd0bb00d66c9f18a20a998101b5df6c8f60L18-R22) **Developer Experience and Documentation** * Added `AGENTS.md` to provide comprehensive guidance for Claude Code and developers, including project overview, build commands, architecture, native bridge APIs, Swift code style, and dependencies. (`AGENTS.md`) * Added a local settings file (`settings.local.json`) to configure permissions for Claude Code, allowing specific Bash commands for iOS builds. (`settings.local.json`) * Updated Swift architecture guidelines to discourage protocol-oriented design unless necessary, favoring dependency injection and composition. (`AGENTS.md`) **User Experience Improvements** * The purchase footer now includes an underline for "Restore Purchase" and a clear message about subscription auto-renewal and cancellation flexibility. (`PurchaseFooterView.swift`) * Improved restore purchase and App Store sync logic to better handle user sign-in prompts and error handling. (`ViewModel+Action.swift`, `Store.swift`) [[1]](diffhunk://#diff-df2cb61867b4ff10dee98d534cf3c94fe8d48ebaef3f219450a9fba26725fdcbL45-R49) [[2]](diffhunk://#diff-df2cb61867b4ff10dee98d534cf3c94fe8d48ebaef3f219450a9fba26725fdcbL58-R73) [[3]](diffhunk://#diff-9f18fbbf15591c56380ce46358089c663ce4440f596db8577de76dc6cd306b54R26-R28) **Minor Fixes and Refactoring** * Made `docId` in `DeleteSessionInput` optional to match GraphQL schema expectations. (`DeleteSessionInput.graphql.swift`) [[1]](diffhunk://#diff-347e5828e46f435d7d7090a3e3eb7445af8c616f663e8711cd832f385f870a9bL14-R14) [[2]](diffhunk://#diff-347e5828e46f435d7d7090a3e3eb7445af8c616f663e8711cd832f385f870a9bL25-R25) * Minor formatting and dependency list updates in `Package.swift`. (`Package.swift`) * Fixed concurrency usage in event streaming for chat manager. (`ChatManager+Stream.swift`) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * New Features * Paywall options now dynamically reflect product data with clearer labels and monthly price calculations. * Added an auto‑renewal note (“cancel anytime”) and underlined “Restore Purchase” for better clarity. * Refactor * Improved purchase/restore flow reliability and UI updates for a smoother experience. * Documentation * Added a comprehensive development guide and updated architecture/style guidance for iOS. * Chores * Introduced local build permissions configuration for iOS development. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
4.6 KiB
4.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is the AFFiNE iOS application built with Capacitor, React, and TypeScript. It's a hybrid mobile app that wraps a React web application in a native iOS shell.
Development Commands
Build and Development
yarn dev- Start development server with live reloadyarn build- Build the web applicationyarn sync- Sync web assets with Capacitor iOS projectyarn sync:dev- Sync with development server (CAP_SERVER_URL=http://localhost:8080)yarn xcode- Open Xcode projectyarn codegen- Generate GraphQL and Rust bindingsxcodebuild -workspace App.xcworkspace -scheme App -destination 'platform=iOS Simulator,name=iPhone 15' build | xcbeautify- Build iOS project with xcbeautify
iOS Build Process
BUILD_TYPE=canary PUBLIC_PATH="/" yarn affine @affine/ios build- Build web assetsyarn affine @affine/ios cap sync- Sync with iOS projectyarn affine @affine/ios cap open ios- Open in Xcode
Live Reload Setup
- Run
yarn devand selectiosfor Distribution option - Run
yarn affine @affine/ios sync:dev - Run
yarn affine @affine/ios cap open ios
Architecture
Core Technologies
- Capacitor 7.x - Native iOS bridge
- React 19 - UI framework
- TypeScript - Language
- Blocksuite - Document editor
- DI Framework - Dependency injection via
@toeverything/infra
Key Directories
src/- React application sourceApp/- Native iOS Swift codedist/- Built web assetscapacitor-cordova-ios-plugins/- Capacitor plugins
Native Bridge Integration
The app exposes JavaScript APIs to native iOS code through window object:
getCurrentServerBaseUrl()- Get current server URLgetCurrentI18nLocale()- Get current localegetAiButtonFeatureFlag()- Check AI button feature flaggetCurrentWorkspaceId()- Get current workspace IDgetCurrentDocId()- Get current document IDgetCurrentDocContentInMarkdown()- Export current doc as markdowncreateNewDocByMarkdownInCurrentWorkspace()- Import markdown as new doc
Swift Code Style
Follow the guidelines in AGENTS.md:
- 2-space indentation
- PascalCase for types, camelCase for properties/methods
- Modern Swift features:
@Observable,async/await,actor - Protocol-oriented design, dependency injection
- Early returns, guard statements for optional unwrapping
Build Configuration
- TypeScript config extends
../../../../tsconfig.web.json - Webpack bundling via
@affine-tools/cli - Capacitor config in
capacitor.config.ts - GraphQL codegen via Apollo
- Rust bindings generated via Uniffi
Dependencies
- Workspace packages:
@affine/core,@affine/component,@affine/env - Capacitor plugins: App, Browser, Haptics, Keyboard
- React ecosystem: React Router, Next Themes
- Storage: IDB, Yjs for collaborative editing
Testing and Quality
- TypeScript strict mode enabled
- ESLint/Prettier configuration from workspace root
- No specific test commands in this package (tests likely in workspace root)
Swift Code Style Guidelines
Core Style
- Indentation: 2 spaces
- Braces: Opening brace on same line
- Spacing: Single space around operators and commas
- Naming: PascalCase for types, camelCase for properties/methods
File Organization
- Logical directory grouping
- PascalCase files for types,
+for extensions - Modular design with extensions
Modern Swift Features
- @Observable macro: Replace
ObservableObject/@Published - Swift concurrency:
async/await,Task,actor,@MainActor - Result builders: Declarative APIs
- Property wrappers: Use line breaks for long declarations
- Opaque types:
somefor protocol returns
Code Structure
- Early returns to reduce nesting
- Guard statements for optional unwrapping
- Single responsibility per type/extension
- Value types over reference types
Error Handling
Resultenum for typed errorsthrows/tryfor propagation- Optional chaining with
guard let/if let - Typed error definitions
Architecture
- Avoid using protocol-oriented design unless necessary
- Dependency injection over singletons
- Composition over inheritance
- Factory/Repository patterns
Debug Assertions
- Use
assert()for development-time invariant checking - Use
assertionFailure()for unreachable code paths - Assertions removed in release builds for performance
- Precondition checking with
precondition()for fatal errors
Memory Management
weakreferences for cyclesunownedwhen guaranteed non-nil- Capture lists in closures
deinitfor cleanup