{"id":25814624,"url":"https://github.com/sunthecoder/lcvaportal","last_synced_at":"2026-04-08T23:33:55.077Z","repository":{"id":278983953,"uuid":"937394697","full_name":"SunTheCoder/LCVAPortal","owner":"SunTheCoder","description":"The LCVA Portal is a native iOS application developed for the Longwood Center for Visual Arts (LCVA). This application serves as a digital gateway to LCVA's art collections, enabling users to explore, interact with, and learn about various artworks in the museum.","archived":false,"fork":false,"pushed_at":"2025-03-11T17:52:06.000Z","size":103020,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-22T23:23:49.044Z","etag":null,"topics":["art","artificial-intelligence","caching","cdn","cloud","firebase","geospatial","ios","microservice","mobile","museum","nosql","optimization","postgresql","records-management","rpc","s3","supabase","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SunTheCoder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-22T23:58:31.000Z","updated_at":"2025-03-11T17:52:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"1791058c-82f9-4a87-9642-bfa3a276a066","html_url":"https://github.com/SunTheCoder/LCVAPortal","commit_stats":null,"previous_names":["sunthecoder/lcvaportal"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SunTheCoder/LCVAPortal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SunTheCoder%2FLCVAPortal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SunTheCoder%2FLCVAPortal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SunTheCoder%2FLCVAPortal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SunTheCoder%2FLCVAPortal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SunTheCoder","download_url":"https://codeload.github.com/SunTheCoder/LCVAPortal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SunTheCoder%2FLCVAPortal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31579055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["art","artificial-intelligence","caching","cdn","cloud","firebase","geospatial","ios","microservice","mobile","museum","nosql","optimization","postgresql","records-management","rpc","s3","supabase","swift","swiftui"],"created_at":"2025-02-28T03:31:18.885Z","updated_at":"2026-04-08T23:33:55.043Z","avatar_url":"https://github.com/SunTheCoder.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LCVA Portal iOS Application\n\n## Overview\nThe LCVA Portal is a native iOS application developed for the Longwood Center for Visual Arts (LCVA). This application serves as a digital gateway to LCVA's art collections, enabling users to explore, interact with, and learn about various artworks in the museum.\n\n![alt text](\u003cScreenRecording_03-11-2025 13-low.gif\u003e) ![alt text](Lcvapreview2-low-5.gif) ![ ](Lcvapreview2-low-3.gif) ![alt text](\u003cScreenRecording_03-11-2025 12-10-14_1-low.gif\u003e) ![alt text](Lcvapreview2-low.gif)\n\n\n## Features\n\n### Collections Management\n- Browse the complete LCVA museum collection\n- Filter artworks by various collections (African Art, American Art, etc.)\n- Create personal collections of favorite artworks\n- Add/remove artworks to personal collections\n- Mark artworks as favorites within collections\n\n### Artist Spotlight\n- Featured artist showcase with media gallery\n- Supports both images and videos\n- Media ordered by curator preference\n- Consistent media presentation across views\n- Efficient media caching and preloading\n- Full-screen media viewer with rotation support\n\n### Art Piece Interaction\n- View detailed information about each artwork\n- High-quality artwork images\n- Artwork metadata (title, artist, era, materials, etc.)\n- Location information for displayed pieces\n- Accessibility features (translations, audio tours, braille labels)\n\n### Social Features\n- Real-time chat discussions about specific artworks\n- User authentication via Firebase\n- Personal user profiles\n- Share thoughts and insights about artworks\n\n### Technical Implementation\n- **Backend Services**:\n  - Supabase for art collection data\n  - Spotlight media management with ordered galleries\n  - Custom RPC functions for optimized queries\n  - Row Level Security (RLS) for data protection\n  - Firebase for user authentication and real-time chat\n  - Cloud storage for high-resolution images and videos (WebP, mp4)\n\n- **Performance Optimizations**:\n\n  - **Media Caching System**:\n    - Custom FileManager-based caching\n  - **Image Caching**:\n    - First-load persistence to disk\n    - Offline image availability\n    - Memory-efficient loading\n    - Specialized image views for different contexts:\n      - Artist Spotlight galleries\n      - On Display section images\n      - Exhibition thumbnails\n      - Collection grid views\n      - List view thumbnails\n  - **Video Caching**:\n    - Concurrent download management\n    - Memory and disk caching\n    - Automatic player cleanup\n    - Download state tracking\n    - Error handling and recovery\n    - Efficient player reuse\n\n  - **Data Preloading**:\n    - Unified PreloadManager\n    - Concurrent artifact and exhibition loading\n    - Background media prefetching\n    - Progress tracking system\n    - Efficient state management via managers\n    - Reduced API calls through caching\n\n- **Loading Architecture**:\n  - Elegant splash screen with animations\n  - Concurrent data loading behind splash\n  - No visible loading indicators\n  - Smooth transition to main content\n  - Minimum display time for branding\n\n- **Network Optimization**:\n  - Single-fetch data persistence\n  - Cached image responses\n  - Bandwidth reduction through local storage\n  - Smart reload policies\n\n- **Data Models**:\n  - UUID-based artifact identification\n  - Structured art piece information\n  - User collection management\n  - Chat message system\n\n- **UI/UX**:\n  - SwiftUI-based interface\n  - Responsive grid and list views\n  - Custom navigation system\n  - Dynamic filtering and search\n\n## Architecture\n- Modern Swift concurrency with async/await\n- MVVM architecture\n- Component-based UI design\n- Real-time data synchronization\n- Efficient data preloading and caching\n\n### Loading Strategy\n```swift\n// Unified PreloadManager\nclass PreloadManager: ObservableObject {\n    static let shared = PreloadManager()\n    \n    func preloadAllContent() async {\n        // 1. Load artifacts\n        // 2. Load exhibitions\n        // 3. Preload images\n    }\n}\n\n// Elegant Splash Screen\nstruct SplashView: View {\n    @ObservedObject var preloadManager = PreloadManager.shared\n    \n    // Beautiful animations while loading\n    // Waits for preloading completion\n    // Smooth transition to main content\n}\n```\n\nThis architecture ensures:\n- Professional first impression\n- No visible loading screens\n- Data ready when needed\n- Efficient resource usage\n- Polished user experience\n\n## Dependencies\n- Firebase\n- FirebaseFirestore\n- SwiftUI\n- Custom Supabase Client with RPC support\n\n## Features\n\n- Firebase Authentication\n- Firestore Database\n- Supabase Integration\n  - Artifact Storage\n  - User Collections\n  - User Profiles\n    - Avatar URLs stored in Supabase users table\n  - Reflections \u0026 Media Storage\n- Real-time Chat\n- Media Upload Support\n  - Images\n  - Videos\n  - Text Reflections\n\n## Database Structure\n\n### Supabase Tables\n- `users`\n  - `id` (from Firebase Auth)\n  - `email`\n  - `name`\n  - `created_at`\n  - `avatar_url` - User's profile image URL\n- `artifacts`\n- `collections`\n- `user_collections`\n- `artifact_reflections`\n- `chat_messages`\n\n### Firebase Collections\n- `users` (legacy, migrating to Supabase)\n- `chats`\n\n## Environment Setup\n\nRequired environment variables:\n- `SUPABASE_URL`\n- `SUPABASE_ANON_KEY`\n- Firebase configuration\n\n## Migration Notes\n\nThe app is gradually migrating user data from Firebase to Supabase:\n- User profiles and avatars now stored in Supabase\n- Chat messages remain in Firebase\n- Media storage handled by Supabase Storage\n\n## Database Functions\n\n### Supabase RPC Functions\n#### Implementation Strategy\nThe app uses a three-tier approach for efficient data management:\n\n1. **ArtifactManager** - Singleton state container\n```swift\n@MainActor\nclass ArtifactManager: ObservableObject {\n    static let shared = ArtifactManager()\n    @Published var artifacts: [Artifact] = []\n    \n    func preloadArtifacts() async {\n        // Preload artifacts at app launch\n    }\n}\n```\n\n2. **App-Level Preloading** - Data ready before user needs it\n```swift\n@main\nstruct LCVAPortalApp: App {\n    @StateObject private var artifactManager = ArtifactManager.shared\n    \n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n                .task {\n                    await artifactManager.preloadArtifacts()\n                }\n                .environmentObject(artifactManager)\n        }\n    }\n}\n```\n\n3. **View-Level Consumption** - Clean, efficient data access\n```swift\nstruct CollectionsView: View {\n    @EnvironmentObject var artifactManager: ArtifactManager\n    \n    var displayedArtPieces: [ArtPiece] {\n        artifactManager.artifacts\n            .filter { $0.on_display }\n            .map(convertToArtPiece)\n    }\n}\n```\n\nThis architecture ensures:\n- Data is loaded once at app launch\n- No redundant network calls\n- Consistent state across views\n- Efficient memory usage\n\n#### Available Functions\n- `get_all_artifacts()`: Retrieves complete artifact collection\n- `get_artifacts_by_collection(collection_name TEXT)`: Filters artifacts by collection\n- `get_exhibition_data()`: Retrieves all exhibitions\n\nExample usage in Swift:\n```swift\n// Fetch all artifacts\nlet artifacts = try await artifactService.fetchAllArtifacts()\n\n// Fetch collection-specific artifacts\nlet collectionArtifacts = try await artifactService.fetchArtifactsByCollection(\n    collectionName: \"African Art\"\n)\n```\n\n## Caching Architecture\n\n### Image Caching Implementation\n```swift\nclass ImageCache {\n    static let shared = ImageCache()\n    private let cacheDirectory: URL\n    \n    func saveImageToDisk(image: UIImage, filename: String)\n    func loadImageFromDisk(filename: String) -\u003e UIImage?\n    func imageExists(filename: String) -\u003e Bool\n}\n```\n\n### Video Caching Implementation\n```swift\nclass VideoCache {\n    static let shared = VideoCache()\n    private let cacheDirectory: URL\n    private var memoryCache: [String: AVPlayer] = [:]\n    private var activeDownloads: [String: Task\u003cVoid, Error\u003e] = [:]\n    \n    func cacheVideo(from url: URL, filename: String) async throws\n    func getCachedVideo(urlString: String, filename: String) -\u003e AVPlayer?\n    func clearCache()\n}\n```\n\n### Specialized Media Views\n```swift\n// Main collection grid images\nstruct CachedCollectionImageView: View {\n    let urlString: String\n    let filename: String\n    // Optimized for grid display\n}\n\n// Thumbnail list images\nstruct CachedCollectionThumbView: View {\n    let urlString: String\n    let filename: String\n    let size: CGFloat\n    // Optimized for list views\n}\n\n// Video player with caching\nstruct CachedVideoPlayer: View {\n    let urlString: String\n    let filename: String\n    // Handles loading, caching, and playback\n}\n```\n\n### Benefits\n- Instant loading of previously viewed media\n- Reduced server load and bandwidth usage\n- Offline functionality for cached content\n- Optimized memory usage\n- Context-specific media handling\n- Concurrent download management\n- Automatic resource cleanup\n\n## Copyright\n© 2024 Bobby \"Sun\" English and Longwood Center for Visual Arts. All rights reserved.\nThis application and its source code are the property of Sun English and LCVA.\nUnauthorized copying, modification, or distribution is prohibited.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunthecoder%2Flcvaportal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunthecoder%2Flcvaportal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunthecoder%2Flcvaportal/lists"}