### Install Tuist CLI using Homebrew Source: https://docs.swiftylaunch.com/basics/tuist-integration Instructions for installing the Tuist command-line interface using Homebrew. This is a prerequisite for using Tuist to manage your Xcode projects. ```bash brew tap tuist/tuist brew install --formula tuist@4.21.1 ``` -------------------------------- ### Add New Module to Project.swift Source: https://docs.swiftylaunch.com/basics/tuist-integration Example of defining a new module (target) within the Project.swift file. This Swift code demonstrates how to specify target name, product type, dependencies, and source files. ```swift func addMyModule() { // Module Name let targetName = "MyModule" // Defining the target let myModuleTarget: Target = .target( name: targetName, // name, as specified above destinations: destinations, // destinations, defined globally product: .framework, // product type bundleId: "\(bundleID).\(targetName)", // specified above deploymentTargets: .iOS(osVersion), // minimum deployment target, defined globally infoPlist: .default, // will use a default info.plist sources: ["Targets/\(targetName)/Sources/**"], // sources folder // resources: ["Targets/\(targetName)/Resources/**"], // resources folder dependencies: [ // included targets (packages, frameworks, modules) sharedKit, // include SharedKit target // analyticsKit, // include AnalyticsKit target TargetDependency .package(product: "Alamofire", type: .runtime), // include Alamofire target ] ) // Add this module to the project as a target appDependencies.append(TargetDependency.target(name: targetName)) // Add external package dependencies at project level // And include it in the target (see dependencies array in target definition) projectPackages .append( .remote( url: "https://github.com/Alamofire/Alamofire.git", requirement: .upToNextMajor(from: "5.9.1") ) ) // Add the target to the project projectTargets.append(myModuleTarget) } ``` -------------------------------- ### Start Firebase Emulators Source: https://docs.swiftylaunch.com/module/backendkit/running-locally Starts the configured Firebase emulators. This command launches the local emulators for services like Cloud Functions, Firestore, and Authentication, making them accessible at specified local URLs. ```bash firebase emulators:start ``` -------------------------------- ### Add Module to Project.swift (Swift) Source: https://docs.swiftylaunch.com/basics/tuist-integration Demonstrates how to add a new module (e.g., 'MyModule') to the project setup in `Project.swift`. This involves calling the module's addition function before `addApp()` and ensuring the module definition function is present. Dependencies include the SwiftyLaunch framework and Tuist. ```swift // ... previous setup and module addition calls addAIKit() addAdsKit() addMyModule() // Call to add the new module addApp() return Project( /* ... */ ) func addApp() { /* ... */ } // ... other module definitions func addMyModule() { /* ... */ } // Definition for the new module ``` -------------------------------- ### Install Firebase CLI Source: https://docs.swiftylaunch.com/module/backendkit/running-locally Installs the Firebase Command Line Interface globally using npm. This is a prerequisite for managing and running Firebase services locally. ```bash npm install -g firebase-tools ``` -------------------------------- ### Initialize Firebase Emulators Source: https://docs.swiftylaunch.com/module/backendkit/running-locally Initializes the Firebase emulators for the project. This command walks through a setup process to select which emulators (Functions, Firestore, Authentication) to enable for local development. ```bash firebase init emulators ``` -------------------------------- ### Usage Example: showInAppNotification with Predefined Style Source: https://docs.swiftylaunch.com/module/sharedkit/in-app-notifications Provides an example of using the `showInAppNotification` function with a predefined `.warning` type to inform the user about a beta feature. This function requires importing SharedKit. ```swift import SharedKit func enableBetaFeature() { // ... enable the beta feature showInAppNotification( .warning, content: .init( title: "This Feature is in Beta", message: "Please report any issues you encounter" ) ) } ``` -------------------------------- ### Generate Xcode Project with Tuist Source: https://docs.swiftylaunch.com/basics/tuist-integration Command to generate or regenerate your Xcode project files using Tuist. Ensure you are in your project's root directory containing the Project.swift file before running. ```bash tuist generate ``` -------------------------------- ### SwiftUI View for Database Interaction Source: https://docs.swiftylaunch.com/module/databasekit/usage-example The DatabaseExampleView is a SwiftUI View that utilizes an EnvironmentObject `DB` to interact with a database. It displays a list of posts, allows for post deletion with authentication checks, and provides navigation to a post creation screen. Dependencies include SwiftUI and the `DB` object. ```swift public struct DatabaseExampleView: View { @EnvironmentObject var db: DB // ... public var body: some View { NavigationStack(path: /* ... */) { List { // ... ForEach(db.posts) { post in // Below is a single post view Section( // Post Creation Date and User ID ("Anonymous" if nil) footer: Text( "(post.creationDate.description) | by (post.postUserID ?? "Anonymous")") ) { HStack { Text(post.title) // ... Button(role: .destructive) { Task { await db.executeIfSignedIn(withUserID: post.postUserID) { await db.deletePost(id: post.id!) } await db.fetchPosts() } } Image(systemName: "trash") } Text(post.content) } } } // ... // Fetch Data when View Appears .onAppear { // ... await db.fetchPosts() // ... } // ... pull down to refresh .toolbar { // ... NavigationLink(value: DBExamplePath.postNew) { Image(systemName: "square.and.pencil") } } .navigationDestination(for: /* ... */) { // ... PostCreationView { // ... await db.fetchPosts() // ... } } } } } ``` -------------------------------- ### Initialize NotifKit in App.swift Source: https://docs.swiftylaunch.com/module/notifkit This code snippet shows how to initialize the NotifKit module by calling a static function on app launch. It ensures that push notification services are set up correctly from the start. ```swift PushNotifications.initOneSignal() ``` -------------------------------- ### SwiftUI Flexible Stack View Usage Example Source: https://docs.swiftylaunch.com/module/sharedkit/views/stack Demonstrates the practical application of the flexible Stack view in SwiftUI, adapting its orientation between VStack and HStack based on the current platform. This example, from AIVisionExampleView in AIKit, shows how to conditionally arrange UI elements for different screen sizes and orientations. ```swift import SwiftUI import SharedKit // ...Other imports struct AIVisionExampleView: View { // ... var body: some View { // VStack on iPhone, HStack on iPad // iPhone: Camera Feed on top, Shutter Button at the bottom // iPad: Camera Feed on the left, Shutter Button on the right Stack(currentPlatform == .phone ? .vertical : .horizontal, spacing: 25) { CameraView() // VStack on iPad, HStack on iPhone Stack(currentPlatform == .phone ? .horizontal : .vertical) { // ...Photos Picker Button Button { // ... } label: { Circle() .fill(.white) .frame(width: 75, height: 75) } .buttonStyle(ShutterButton()) // ... Selfie / Rear Camera Switch Button } } } } ``` -------------------------------- ### Ad Impression and Click Tracking with AnalyticsKit (Swift) Source: https://docs.swiftylaunch.com/basics/swifty-launch-modules Illustrates how to integrate AnalyticsKit within an AdsKit module to track user ad interactions. This example shows a Swift extension conforming to GADNativeAdDelegate, capturing ad impressions and clicks using Analytics.capture. ```Swift import AnalyticsKit import GoogleMobileAds extension NativeAdBannerViewModel: GADNativeAdDelegate { /// Track when your users views an ad public func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) { Analytics.capture(.info, id: "ad_impression", source: .adsKit) } /// Track when your users click on an ad public func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) { Analytics.capture(.info, id: "ad_click", source: .adsKit) } } ``` -------------------------------- ### AnalyticsKit: Example of Capturing an Event (Swift) Source: https://docs.swiftylaunch.com/module/analyticskit/track-events-and-errors Demonstrates how to use the `Analytics.capture()` function to track a 'picture_liked' event. This example includes the event type, a unique ID, a descriptive string, the event source, and the originating view, showcasing practical application of the `capture` function. ```swift import AnalyticsKit func likePicture(withID pictureID: String) { // ... picture liking logic Analytics.capture( .success, id: "picture_liked", longDescription: "User liked picture with ID \(pictureID)", source: .general, fromView: "HomeFeedView" ) } ``` -------------------------------- ### Create Supabase 'posts' Table and Columns Source: https://docs.swiftylaunch.com/project-setup/databasekit%2Bauthkit-supabase Defines the schema for the 'posts' table in Supabase, including primary key, text fields for title and content, and timestamp/UUID fields for creation date and user ID. It also configures default values and RLS settings. ```sql CREATE TABLE public.posts ( id bigint generated by default as identity primary key, title text NOT NULL, content text NOT NULL, creationDate timestamp with time zone DEFAULT now(), postUserID uuid DEFAULT auth.uid() ); ``` -------------------------------- ### Control Voice Recording Start/Stop (Swift) Source: https://docs.swiftylaunch.com/module/aikit/ai-translator-example This Swift code demonstrates the ViewModel responsible for controlling the voice recording process. It interacts with the VoiceRecordingManager to start and stop recording, passing a success flag to determine subsequent actions like transcription. Dependencies include ObservableObject and VoiceRecordingManager. ```swift class VoiceRecordingViewModel: ObservableObject { /// The VoiceRecordingManager that will handle the recording @ObservedObject var voiceRecordingManager = VoiceRecordingManager() // ... func shouldStartRecording() { // ... voiceRecordingManager.startRecording() // ... } func shouldStopRecording() { // ... voiceRecordingManager.stopRecording(success: true) // ... } // ... } ``` -------------------------------- ### Fetch All Posts Function (Swift) Source: https://docs.swiftylaunch.com/module/databasekit/usage-example Implements the `fetchPosts()` function within the `DB` class extension. This asynchronous function is responsible for retrieving all posts from the database and updating the `posts` published property. It ensures that UI updates are handled on the main actor. ```swift extension DB { @MainActor public func fetchPosts() async { } } ``` -------------------------------- ### Initiate Voice Recording with Microphone Access (Swift) Source: https://docs.swiftylaunch.com/module/aikit/ai-translator-example This Swift code snippet shows how to initiate voice recording when a button is released. It uses a LongPressGesture to detect the release and checks for microphone access before starting the recording via the VoiceRecordingViewModel. Dependencies include SwiftUI and the VoiceRecordingViewModel. ```swift struct AIVoiceExampleView: View { @StateObject private var vm = AIVoiceExampleViewModel() @StateObject private var voiceRecordingVM = VoiceRecordingViewModel() var body: some View { VStack { Button { // Translate button released -> call the function to translate the voice recording vm.releasedTranslateButton(voiceRecordingVM: voiceRecordingVM) } label: { /* ... */ } .buttonStyle(TransateButton()) // ... // If the user presses for at least 0.2 and gave us microphone access // -> call our voice recording function that will initiate recording .simultaneousGesture( LongPressGesture(minimumDuration: 0.2).onEnded { _ in askUserFor(.microphoneAccess) { voiceRecordingVM.shouldStartRecording() } onDismiss: { /* ... */ } }) } } } ``` -------------------------------- ### Define DB Environment Object (Swift) Source: https://docs.swiftylaunch.com/module/databasekit/usage-example Defines the `DB` environment object, which is an `ObservableObject` responsible for managing posts. It includes a published array `posts` to hold `PostData` objects fetched from the database. This is a core component for database interaction in the application. ```swift @MainActor public class DB: ObservableObject { @Published var posts: [PostData] = [] } ``` -------------------------------- ### Create Signed-In Post Function (Swift) Source: https://docs.swiftylaunch.com/module/databasekit/usage-example Implements the `addSignedPost()` function to create a new post associated with a logged-in user. This asynchronous function takes a title and content, and sets the `postUserID` to the currently logged-in user's ID (requires AuthKit integration). It returns a boolean indicating success. ```swift extension DB { public func addSignedPost(title: String, content: String) async -> Bool { } } ``` -------------------------------- ### Define PostData Structure (Swift) Source: https://docs.swiftylaunch.com/module/databasekit/usage-example Defines the `PostData` structure, which represents the data model for a post. It conforms to `Codable`, `Identifiable`, and `Equatable` protocols, allowing for easy encoding/decoding, identification, and comparison. It includes fields for post ID, title, content, creation date, and user ID. ```swift struct PostData: Codable, Identifiable, Equatable { @DocumentID var id: String? let title: String let content: String let creationDate: Date let postUserID: String? } ``` -------------------------------- ### Initialize RevenueCat with API Key from Property List (Swift) Source: https://docs.swiftylaunch.com/module/sharedkit/helper-functions/get-property-list-entry Demonstrates how to initialize the RevenueCat SDK using an API key retrieved from a property list file. The `initRevenueCat` function uses `getPlistEntry` to fetch the API key and configures Purchases. It includes error handling to capture and report initialization failures. ```swift import AnalyticsKit import RevenueCat import SharedKit public class InAppPurchases: ObservableObject { @discardableResult // Initialize RevenueCat with the API key from the property list // Returns true if everything went well, false otherwise // Is called from the main app's AppDelegate public static func initRevenueCat() -> Bool { do { // get the API key ("REVENUECAT_API_KEY") from the property list ("RevenueCat-Info") let apiKey = try getPlistEntry("REVENUECAT_API_KEY", in: "RevenueCat-Info") // Initialize RevenueCat with the api key Purchases.configure(withAPIKey: apiKey) // return true if everything went well return true } catch { // caputre an error if something went wrong and return false Analytics.capture( .error, id: "rc_setup", longDescription: "[IAP] RevenueCat Init Error: \(error)", source: .iap ) return false } } } ``` -------------------------------- ### Initialize App and Environment Objects in Swift Source: https://docs.swiftylaunch.com/module/app Sets up the main application structure by initializing environment objects like DB and InAppPurchases, and attaching view modifiers for handling permission requests and paywalls. It also defines the app delegate for managing the app lifecycle. ```swift @main struct MainApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject var db = DB() @StateObject var iap = InAppPurchases() // ... var body: some Scene { WindowGroup { ZStack { ContentView() // ... .modifier(ShowRequestSheetWhenNeededModifier()) // ... .modifier(ShowPaywallSheetWhenCalledModifier(iap)) // ... .environmentObject(db) .environmentObject(iap) } } } } ``` -------------------------------- ### Example: Capture Event in BackendKit Source: https://docs.swiftylaunch.com/module/backendkit/analyticskit-integration This TypeScript example demonstrates capturing and sending an 'info' event using AnalyticsKit when a function like `fetchAllUsers` is called in BackendKit. It includes retrieving the user ID from the request and structuring the event data. ```typescript export const fetchAllUsers = onCall(async (request) => { // get user ID from request (if available) let fromUid = request.auth?.uid; Analytics.captureEvent({ data: { eventType: "info", id: "fetch_all_users", longDescription: "Fetching all users from the database", source: "db", }, fromUserID: fromUid, }); // execute the function }); ``` -------------------------------- ### SwiftUI View for AI Vision Capture Source: https://docs.swiftylaunch.com/module/aikit/ai-vision-example This SwiftUI view, AIVisionExampleView, handles user interaction for capturing images and initiating AI-based descriptions. It integrates with CameraViewModel and AIVisionExampleViewModel, and observes changes in the captured image to trigger backend processing. Dependencies include SwiftUI, CameraViewModel, and AIVisionExampleViewModel. ```swift // ... struct AIVisionExampleView: View { // ... @StateObject private var vm = AIVisionExampleViewModel() @StateObject private var cameraViewModel = CameraViewModel() @StateObject private var voiceRecordingViewModel = VoiceRecordingViewModel() // ... var body: some View { VStack { // ... camera feed HStack { // ... photos picker Button { vm.releasedShutterButton(cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel) } label: { // ... } .buttonStyle(ShutterButton()) // ... // ... flip camera button } } .onChange(of: cameraViewModel.capturedImage) { vm.detectedCapturedCameraImageUpdate( db: db, cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel ) } } } ``` -------------------------------- ### SwiftUI InAppPurchaseView Usage with VideoPlayerAlphaView - RevenueCatUI, SharedKit Source: https://docs.swiftylaunch.com/module/sharedkit/views/hevc-video-with-transparency An example of how to integrate the VideoPlayerAlphaView within a SwiftUI view, specifically demonstrating its use in the `InAppPurchaseView` paywall hero section. This example utilizes `RevenueCatUI`, `SharedKit`, and `SwiftUI`. ```swift import RevenueCat import RevenueCatUI import SharedKit import SwiftUI // ...Other imports struct InAppPurchaseView: View { // ... var body: some View { InAppPurchaseCarousel(heroTitle: paywallHeroTitle) .paywallFooter(purchaseCompleted: onPurchaseCompleted) // RevenueCatUI's Paywall Footer } private struct InAppPurchaseCarousel: View { private let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect() var body: some View { TabView(selection: $page) { PaywallHeroView(title: heroTitle) // ...Second Paywall Carousel View // ...Third Paywall Carousel View } .accentBackground(strong: true) .tabViewStyle(.page(indexDisplayMode: .never)) .onReceive(timer) { // ...auto scroll pages } } } private struct PaywallHeroView: View { // ... var body: some View { VStack { VideoPlayerAlphaView( url: Bundle.module.url(forResource: "paywall-hero-vid", withExtension: "mov")!, keepsAspectRatio: true ) // ...Paywall Hero Title } .ignoresSafeArea(.container, edges: .top) } } } ``` -------------------------------- ### ViewModel for AI Vision Image Processing Source: https://docs.swiftylaunch.com/module/aikit/ai-vision-example The AIVisionExampleViewModel class orchestrates the AI vision workflow. It captures images via CameraViewModel, sends them to a backend for description using a DB service, and handles the response by playing audio feedback. Key inputs include the captured image and a processing command, with audio output as a primary result. Dependencies include CameraViewModel, VoiceRecordingViewModel, and a DB service. ```swift // ... class AIVisionExampleViewModel: ObservableObject { // ... func releasedShutterButton(cameraVM: CameraViewModel, voiceRecordingVM: VoiceRecordingViewModel) { // ... cameraVM.captureImage() // ... } @MainActor func detectedCapturedCameraImageUpdate(db: DB, cameraVM: CameraViewModel, voiceRecordingVM: VoiceRecordingViewModel) { // ... guard let capturedImageBase64 = capturedImg.base64 else { /* ... */ } // ... if let result = await db.processImageWithAI( jpegImageBase64: capturedImageBase64, processingCommand: voiceRecordingVM.currentAudioTranscription ?? "Describe exactly what you see.", readResultOutLoud: true // hard-coded to always read out loud ) { /// If we got audio from the server (we should get it if we set `readResultOutLoud`to true), read the audio out loud. Otherwise show the result as a text in a notification if let audio = result.audio { voiceRecordingVM.generalAudioModel.playAudio(base64Source: audio) } else { showInAppNotification(/* show in-app notification if not reading out loud */) } } else { // ... error handling } // ... } // ... } ``` -------------------------------- ### Backend Example: Send Push Notification with In-App Data Source: https://docs.swiftylaunch.com/module/backendkit/notifkit-integration An example of a backend function using `onCall` that sends a push notification to a user. It retrieves user information, processes request data for the message and recipient, and includes custom data for in-app notifications. ```typescript export const sendNotificationTo = onCall(async (request) => { let fromUid = request.auth?.uid; // ... try { if (!fromUid) { throw new Error("User Not Logged In"); } // get current user data const user = await getAuth().getUser(fromUid); // get receiver user ID from request let toUid = request.data?.userID as string; if (!toUid) { // ... throw new Error("No Receiver UserID provided"); } // get message from request, if not available, set to "Empty Message" let message = request.data?.message as string | "Empty Message"; // send notification to the user await PushNotifications.sendNotificationToUserWithID({ userID: toUid, data: { title: `Message from ${user.displayName || fromUid}`, message: message, additionalData: { // show in-app notification with these params if app is open inAppSymbol: "bolt.fill", inAppColor: "#ae0000", inAppSize: "compact", inAppHaptics: "error", }, }, }); // ... } catch (error) { // ... throw new Error("Server Error"); } return true; }); ``` -------------------------------- ### Example: Check User Premium Status with Cloud Functions (TypeScript) Source: https://docs.swiftylaunch.com/module/backendkit/inapppurchasekit-integration An example of how to use the `doesUserHavePremium` function within a Firebase Cloud Function (`onCall`). It retrieves the authenticated user's ID and checks their premium status. It includes error handling for unauthenticated users. ```typescript export const doIHavePremium = onCall(async (request) => { let requestingUserID = request.auth?.uid; if (!requestingUserID) { throw new Error("You must be logged in"); } return await InA‚ppPurchases.doesUserHavePremium(requestingUserID); }); ``` -------------------------------- ### Define Onboarding Pages (SwiftUI) Source: https://docs.swiftylaunch.com/module/app/views/onboarding-view This code snippet shows how to define an array of `AnyView` objects that represent the individual pages of the onboarding experience. You can replace the placeholder `HeroView` instances with your custom views. Ensure the `onboardingPages` array correctly reflects the number of views you intend to display. ```swift private let onboardingPages: [AnyView] = [ AnyView( HeroView( sfSymbolName: "scribble.variable", title: "Onboarding Page 1", subtitle: "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit, sed do.", bounceOnAppear: true ) ), AnyView( /* Hero View 2 */ ), AnyView( /* Hero View 3 */ ), ] ``` -------------------------------- ### Example Usage of captureTaps View Modifier Source: https://docs.swiftylaunch.com/module/analyticskit/capture-taps Demonstrates how to apply the `captureTaps` view modifier to a SwiftUI `LikeButton` within a `PostView`. This example shows how to pass the `tapTargetId` and `fromView` arguments to track taps specifically on the like button within the context of the post view. ```swift import SwiftUI import AnalyticsKit struct PostView: View { var body: some View { VStack { Image( /* image */ ) LikeButton( /* likes */ ) .captureTaps("like_button", fromView: "PostView") CommentSection( /* comments */ ) } } } ``` -------------------------------- ### SwiftUI Usage Example: Applying Squircle to an Image Source: https://docs.swiftylaunch.com/module/sharedkit/view-modifier/squircle Demonstrates how to use the '.squircle()' View Modifier in a SwiftUI view. This example shows an `Image` being resized and then shaped into a squircle using the custom modifier, with a specified width of 150 points. It's part of a larger `SignInHeroSection` within a `SignInView`, utilizing `SharedKit` and `SwiftUI`. ```swift // ... other imports import SharedKit import SwiftUI struct SignInHeroSection: View { var body: some View { VStack { Image("AppIcon-Preview") .resizable() .squircle(width: 150) .padding(.bottom, 10) Text(Constants.AppData.appName) .font(.largeTitle) .bold() Text(Constants.AppData.appDescription) .font(.callout) .multilineTextAlignment(.center) .foregroundStyle(.secondary) } } } public struct SignInView: View { // ... var body: some View { // ... other code VStack { SignInHeroSection() // ... EmailInputFields() // ... SignUpButtons() } // ... other code } } ``` -------------------------------- ### Use CommonTextField Style (Swift) Source: https://docs.swiftylaunch.com/module/sharedkit/ui/textfield-style Provides an example of how to apply the `CommonTextField` style to `TextField` views in SwiftUI. It demonstrates both the default usage and the disabled state. ```swift VStack (spacing: 20) { TextField("Test TextField", text: .constant("Hello")) .textFieldStyle(CommonTextField()) TextField("Test TextField", text: .constant("Hello")) .textFieldStyle(CommonTextField(disabled: true)) } ``` -------------------------------- ### Access Subscription State Source: https://docs.swiftylaunch.com/module/inapppurchasekit Provides the current subscription state of the user, which can be either '.notSubscribed' or '.subscribed'. This state is automatically updated by a listener initiated during the module's setup. ```swift import SwiftyPurchaseKit // In InAppPurchases.swift @Published public private(set) var subscriptionState: SubscriptionState = .notSubscribed ``` -------------------------------- ### Implement Onboarding View Structure (SwiftUI) Source: https://docs.swiftylaunch.com/module/app/views/onboarding-view This snippet demonstrates the core structure of the `OnboardingView` using SwiftUI's `View` protocol. It utilizes a `TabView` to manage the carousel of onboarding pages, driven by the `pageIndex` state variable. The `ForEach` loop iterates through the defined pages, and the `tabViewStyle` is set to `.page(indexDisplayMode: .never)` to hide default page indicators. ```swift struct OnboardingView: View { @State var pageIndex: Int = 0 // ... var body: some View { VStack { TabView(selection: $pageIndex) { ForEach(0..<3) { index in // <- Add the count here when adding or removing views in onboardingPages above onboardingPages[index] .tag(index) } } .tabViewStyle(.page(indexDisplayMode: .never)) // don't show the page dots // ... button to continue } // ... } } ``` -------------------------------- ### Show In-App Notification Example (Swift) Source: https://docs.swiftylaunch.com/module/sharedkit/in-app-notifications Demonstrates how to use the `showInAppNotification` function to display a notification with a title, message, and custom style. Requires importing the SharedKit module. ```swift import SharedKit func greetingMessage() { showInAppNotification( content: .init( title: "Hello World!", message: "This is a regular notification size." ), style: .init( sfSymbol: "bell.badge.fill", symbolColor: .red, size: .normal ) ) } ``` -------------------------------- ### Manage Onboarding Appearance Logic (SwiftUI) Source: https://docs.swiftylaunch.com/module/app/views/onboarding-view This `ViewModifier` checks `UserDefaults` to determine if the onboarding screen should be displayed. It uses `@AppStorage` to access the `lastAppVersionAppWasOpenedAt` key. The onboarding is shown if this value is 'NONE', indicating a first-time launch. The modifier transitions between the onboarding view and the main content using an opacity effect. ```swift struct ShowOnboardingViewOnFirstLaunchEverModifier: ViewModifier { @AppStorage(Constants.UserDefaults.General.lastAppVersionAppWasOpenedAt) private var lastAppVersionAppWasOpenedAt: String = "NONE" @State private var showOnboarding: Bool = false func body(content: Content) -> some View { Group { if showOnboarding { OnboardingView { withAnimation(.bouncy) { showOnboarding = false } } .transition(.opacity) } else { content .transition(.opacity) } } .onAppear { // ... self.showOnboarding = lastAppVersionAppWasOpenedAt == "NONE" // ... } } } ``` -------------------------------- ### POST /analyzeImageContents Source: https://docs.swiftylaunch.com/module/aikit/ai-vision-example Analyzes an image using an AI model based on a provided command. Supports returning the result as text or as text with an accompanying audio file. ```APIDOC ## POST /analyzeImageContents ### Description This endpoint processes an image using AI. It takes a base64 encoded image and a natural language processing command as input. The AI analyzes the image according to the command and returns a textual response. Optionally, the API can also convert the textual response into speech and return it as a base64 encoded MP3 audio string. ### Method POST ### Endpoint /analyzeImageContents ### Parameters #### Request Body - **imageBase64** (string) - Required - The image to be analyzed, encoded in base64 format. - **processingCommand** (string) - Required - The natural language prompt or command for the AI to process the image. - **readResultOutLoud** (boolean) - Optional - If true, the AI's response will be converted to speech and returned as base64 encoded MP3 audio. Defaults to false. ### Request Example ```json { "imageBase64": "/9j/4AAQSkZJRgABAQEASgBPAAD...", "processingCommand": "Describe the main objects in this image.", "readResultOutLoud": true } ``` ### Response #### Success Response (200) - **message** (string) - The AI's textual analysis of the image. - **audio** (string | null) - A base64 encoded MP3 string of the AI's response if `readResultOutLoud` was set to true, otherwise null. #### Response Example ```json { "message": "The image shows a cat sitting on a windowsill.", "audio": "JVBERi0xLjQKJ..." } ``` #### Error Response (e.g., 400, 500) - **error** (string) - A message describing the error. #### Error Response Example ```json { "error": "Invalid image format provided." } ``` ``` -------------------------------- ### Initialize PostHog with Session Replay Enabled (Swift) Source: https://docs.swiftylaunch.com/module/analyticskit/session-recordings This Swift code snippet demonstrates how to initialize the PostHog SDK with session replay and screenshot mode enabled. It configures `sessionReplay` to `true`, `screenshotMode` to `true`, and disables automatic masking for images and text inputs. This setup is crucial for capturing user session recordings within your application. Ensure proper error handling is in place. ```swift extension Analytics { static public func initPostHog() { do { // ... initial setup config.sessionReplay = true config.sessionReplayConfig.screenshotMode = true config.sessionReplayConfig.maskAllImages = false config.sessionReplayConfig.maskAllTextInputs = false PostHogSDK.shared.setup(config) } catch { print("[ANALYTICS] PostHog Init Error: (error.localizedDescription)") return } } } ``` -------------------------------- ### Initialize PostHog Analytics with API Key Source: https://docs.swiftylaunch.com/module/analyticskit Initializes the PostHog SDK using API key and host from PostHog-Info.plist. It configures automatic screen view tracking to be disabled, as manual tracking is preferred, and enables experimental session replays. ```swift extension Analytics { static public func initPostHog() { do { let apiKey = try getPlistEntry("POSTHOG_API_KEY", in: "PostHog-Info") let host = try getPlistEntry("POSTHOG_HOST", in: "PostHog-Info") let config = PostHogConfig(apiKey: apiKey, host: host) // Doesn't work well with SwiftUI. We'll manually track screen views via the .captureViewActivity() Modifier config.captureScreenViews = false // EXPERIMENTAL SESSION REPLAYS: // https://posthog.com/docs/session-replay/mobile config.sessionReplay = true config.sessionReplayConfig.screenshotMode = true PostHogSDK.shared.setup(config) } catch { print("[ANALYTICS] PostHog Init Error: (error.localizedDescription)") return } } } ``` -------------------------------- ### Override Page Metadata in Next.js Source: https://docs.swiftylaunch.com/web/seo This example shows how to override specific metadata values, such as the page title, by passing arguments to the `getMetadata` function. This allows for per-page customization while maintaining the convenience of default settings. ```typescript import { getMetadata } from "@/lib/getMetadata"; export const metadata = getMetadata({ title: "My Custom Title" }); ``` -------------------------------- ### NotifKit Integration in BackendKit Source: https://docs.swiftylaunch.com/module/backendkit/notifkit-integration This section covers the integration of NotifKit for sending push notifications via BackendKit. It includes importing the module, defining the notification structure, and provides a backend usage example. ```APIDOC ## NotifKit Integration in BackendKit This guide explains how to send push notifications to your users using the pre-built NotifKit functions within BackendKit. ### Import NotifKit To utilize NotifKit functionalities, you must first import `PushNotifications` into your file. ```typescript import * as PushNotifications from "./NotifKit/PushNotifications"; ``` ### Function Definition: `sendNotificationToUserWithID` This function allows you to send a push notification to a specific user using their ID. **File:** `PushNotifications.ts` ```typescript export async function sendNotificationToUserWithID({ userID, data, }: { userID: string; data: NotificationReadableData; }) {} ``` **Parameters:** * **`userID`** (string) - Required - The unique identifier of the user to receive the notification. This can be the Firebase User ID for the currently authenticated user or a OneSignal User ID for a different user. * **`data`** (NotificationReadableData) - Required - The content and metadata of the notification. #### `NotificationReadableData` Definition **File:** `PushNotifications.ts` ```typescript export type NotificationReadableData = { title: string; message: string; additionalData?: InAppNotificationAdditionalData; }; ``` **Fields:** * **`title`** (string) - Required - The title of the push notification. * **`message`** (string) - Required - The main content of the push notification. * **`additionalData`** (InAppNotificationAdditionalData) - Optional - Additional data to configure in-app notification display when the app is open. ##### `InAppNotificationAdditionalData` Definition This object defines the appearance and behavior of in-app notifications when the app is active. **File:** `PushNotifications.ts` ```typescript type InAppNotificationAdditionalData = { inAppSymbol: SFSymbol; // Symbol to show in the in-app notification inAppColor: string; // in HEX inAppSize?: "normal" | "compact"; // defaults to normal inAppHaptics?: "success" | "warning" | "error"; // defaults to warning }; ``` **Fields:** * **`inAppSymbol`** (SFSymbol) - Required - The SF Symbol name for the in-app notification icon. * **`inAppColor`** (string) - Required - The color of the in-app notification banner in HEX format. * **`inAppSize`** (string) - Optional - The size of the in-app notification. Defaults to `"normal"`. * **`inAppHaptics`** (string) - Optional - The haptic feedback type for the in-app notification. Defaults to `"warning"`. ### Usage Example This backend example demonstrates sending a push notification with custom data, including parameters for an in-app notification display. ```typescript import * as PushNotifications from "./NotifKit/PushNotifications"; import { onCall } from "firebase-functions/v2/https"; import { getAuth } from "firebase-admin/auth"; export const sendNotificationTo = onCall(async (request) => { let fromUid = request.auth?.uid; // ... other setup if needed try { if (!fromUid) { throw new Error("User Not Logged In"); } const user = await getAuth().getUser(fromUid); let toUid = request.data?.userID as string; if (!toUid) { throw new Error("No Receiver UserID provided"); } let message = request.data?.message as string | "Empty Message"; await PushNotifications.sendNotificationToUserWithID({ userID: toUid, data: { title: `Message from ${user.displayName || fromUid}`, message: message, additionalData: { inAppSymbol: "bolt.fill", inAppColor: "#ae0000", inAppSize: "compact", inAppHaptics: "error", }, }, }); // ... success handling } catch (error) { // ... error handling throw new Error("Server Error"); } return true; }); ``` **Explanation:** This function (`sendNotificationTo`) is triggered via a Firebase Cloud Function callable. It verifies the sender's authentication, retrieves sender details, extracts the recipient's `userID` and `message` from the request data, and then uses `PushNotifications.sendNotificationToUserWithID` to send the notification. The `additionalData` object configures the notification to appear as an in-app alert with specific visual and haptic feedback if the app is open. ``` -------------------------------- ### SwiftUI View for AI Vision Capture and Voice Input Source: https://docs.swiftylaunch.com/module/aikit/ai-vision-example This SwiftUI view, AIVisionExampleView, manages the user interface for capturing images and handling voice input. It integrates CameraViewModel for image capture and VoiceRecordingViewModel for audio processing. The view uses gestures to detect long presses for recording and onChange modifiers to react to captured images and audio transcriptions, triggering corresponding actions in the AIVisionExampleViewModel. ```swift struct AIVisionExampleView: View { // ... @StateObject private var vm = AIVisionExampleViewModel() @StateObject private var cameraViewModel = CameraViewModel() @StateObject private var voiceRecordingViewModel = VoiceRecordingViewModel() // ... var body: some View { VStack { // ... camera feed HStack { // ... photos picker Button { // long press over vm.releasedShutterButton(cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel) } label: { // ... } .buttonStyle(ShutterButton()) .simultaneousGesture( // gesture to detect long press LongPressGesture(minimumDuration: 0.2).onEnded { _ in askUserFor(.microphoneAccess) { voiceRecordingViewModel.shouldStartRecording() } onDismiss: { showInAppNotification( /* ... no mic access warning */ ) } }) // ... // ... flip camera button } } .onChange(of: cameraViewModel.capturedImage) { vm.detectedCapturedCameraImageUpdate( db: db, cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel ) } .onChange(of: voiceRecordingViewModel.currentAudioTranscription) { vm.detectedAudioTranscriptionUpdate( cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel ) } } } ``` -------------------------------- ### Display App Version in SwiftUI View Source: https://docs.swiftylaunch.com/module/sharedkit/app-wide-constants Demonstrates how to display the app version constant within a SwiftUI view. It imports SwiftUI and SharedKit to access the `Constants.AppData.appVersion` static property. This example shows a simple text display. ```swift import SwiftUI import SharedKit struct WhatsNewView: View { // ... var body: some View { ScrollView { // ... VStack(alignment: .leading) { Text("Version \(Constants.AppData.appVersion)") // ... Text("What's new") // ... } // ... } // ... } } ``` -------------------------------- ### Request Camera Access in SwiftUI View Source: https://docs.swiftylaunch.com/module/sharedkit/request-permissions Demonstrates how to use the `.requireCapabilityPermission()` modifier to request camera access. The `onSuccess` closure is executed once permission is granted, allowing the app to start the camera feed. This modifier is attached to the `CameraView`. ```swift import SwiftUI import SharedKit // Other imports struct AIVisionExampleView: View { // ... /// View Model to control this View @StateObject private var vm = AIVisionExampleViewModel() /// Interact with the camera @StateObject private var cameraViewModel = CameraViewModel() // ... VStack(spacing: 25) { CameraView() .requireCapabilityPermission( of: .cameraAccess, onSuccess: { // got access to camera -> start feed vm.gotCameraPermissions(cameraVM: cameraViewModel) } ) HStack { // ... Button { // Once the user presses the button and releases it, we tell that to our ViewModel vm.releasedShutterButton(cameraVM: cameraViewModel, voiceRecordingVM: voiceRecordingViewModel) } label: { Circle() .fill(.white) .frame(width: 75, height: 75) } .buttonStyle(ShutterButton()) // ... } } } ``` -------------------------------- ### Supabase RLS Policy: Enable Write Access for Authenticated Users Source: https://docs.swiftylaunch.com/project-setup/databasekit%2Bauthkit-supabase This SQL policy allows authenticated users to insert (write) data into the 'posts' table. It is a permissive policy that applies to users with the 'authenticated' role. ```sql CREATE POLICY "Enable write access for authenticated users" ON "public"."posts" FOR INSERT WITH CHECK (true); ``` -------------------------------- ### Displaying Sign-In Interface with SignInView Source: https://docs.swiftylaunch.com/module/authkit/sign-in-with-apple-flow Presents the user interface for signing in, allowing navigation through different sign-in flows like email signup. It utilizes `NavigationStack` for managing the navigation path and integrates with `DB` for authentication state. ```swift // ... public struct SignInView: View { @ObservedObject var db: DB // ... public var body: some View { NavigationStack(path: $signInFlowPath) { // ... VStack { // ... sign in hero section // ... sign in fields SignUpButtons(shouldShowEmailSignUpScreen: { signInFlowPath.append(SignInFlowPath.emailSignUp) }) } // ... } // ... } } ```