diff --git a/SelfieCam.xcodeproj/project.pbxproj b/SelfieCam.xcodeproj/project.pbxproj index 8a4363a..f4638dd 100644 --- a/SelfieCam.xcodeproj/project.pbxproj +++ b/SelfieCam.xcodeproj/project.pbxproj @@ -32,8 +32,8 @@ /* Begin PBXFileReference section */ EA836ABF2F0ACE8A00077F87 /* Selfie Cam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Selfie Cam.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - EA836ACC2F0ACE8B00077F87 /* Selfie Cam.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Selfie Cam.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - EA836AD62F0ACE8B00077F87 /* Selfie Cam.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Selfie Cam.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + EA836ACC2F0ACE8B00077F87 /* SelfieCamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EA836AD62F0ACE8B00077F87 /* SelfieCamUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EACONFIG002 /* SelfieCam/Configuration/Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SelfieCam/Configuration/Debug.xcconfig; sourceTree = SOURCE_ROOT; }; EACONFIG003 /* SelfieCam/Configuration/Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SelfieCam/Configuration/Release.xcconfig; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -100,8 +100,8 @@ isa = PBXGroup; children = ( EA836ABF2F0ACE8A00077F87 /* Selfie Cam.app */, - EA836ACC2F0ACE8B00077F87 /* Selfie Cam.xctest */, - EA836AD62F0ACE8B00077F87 /* Selfie Cam.xctest */, + EA836ACC2F0ACE8B00077F87 /* SelfieCamTests.xctest */, + EA836AD62F0ACE8B00077F87 /* SelfieCamUITests.xctest */, ); name = Products; sourceTree = ""; @@ -164,7 +164,7 @@ packageProductDependencies = ( ); productName = SelfieCamTests; - productReference = EA836ACC2F0ACE8B00077F87 /* Selfie Cam.xctest */; + productReference = EA836ACC2F0ACE8B00077F87 /* SelfieCamTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; EA836AD52F0ACE8B00077F87 /* SelfieCamUITests */ = { @@ -187,7 +187,7 @@ packageProductDependencies = ( ); productName = SelfieCamUITests; - productReference = EA836AD62F0ACE8B00077F87 /* Selfie Cam.xctest */; + productReference = EA836AD62F0ACE8B00077F87 /* SelfieCamUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; /* End PBXNativeTarget section */ @@ -432,7 +432,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; @@ -442,8 +442,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_IDENTIFIER)"; + PRODUCT_MODULE_NAME = SelfieCam; PRODUCT_NAME = "$(PRODUCT_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES; @@ -462,7 +463,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; @@ -472,8 +473,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_IDENTIFIER)"; + PRODUCT_MODULE_NAME = SelfieCam; PRODUCT_NAME = "$(PRODUCT_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES; @@ -490,13 +492,13 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 26.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "$(TESTS_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(PRODUCT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = NO; @@ -512,13 +514,13 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 26.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "$(TESTS_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(PRODUCT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = NO; @@ -533,12 +535,12 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "$(UITESTS_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(PRODUCT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = NO; @@ -553,12 +555,12 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "$(UITESTS_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(PRODUCT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = NO; diff --git a/SelfieCam.xcodeproj/xcshareddata/xcschemes/SelfieCam.xcscheme b/SelfieCam.xcodeproj/xcshareddata/xcschemes/SelfieCam.xcscheme index cc5f39d..031c14d 100644 --- a/SelfieCam.xcodeproj/xcshareddata/xcschemes/SelfieCam.xcscheme +++ b/SelfieCam.xcodeproj/xcshareddata/xcschemes/SelfieCam.xcscheme @@ -36,7 +36,7 @@ @@ -47,7 +47,7 @@ diff --git a/SelfieCam/Resources/Localizable.xcstrings b/SelfieCam/Resources/Localizable.xcstrings index 42bb59d..4204e7a 100644 --- a/SelfieCam/Resources/Localizable.xcstrings +++ b/SelfieCam/Resources/Localizable.xcstrings @@ -997,7 +997,6 @@ }, "Debug mode: Purchase simulated!" : { "comment" : "Announcement posted to VoiceOver when a premium purchase is simulated in debug mode.", - "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "es-MX" : { @@ -1022,7 +1021,6 @@ }, "Debug mode: Restore simulated!" : { "comment" : "Accessibility announcement when restoring purchases in debug mode.", - "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "es-MX" : { @@ -1125,10 +1123,6 @@ "comment" : "Subtitle for a feature row in the \"Welcome\" view, describing the ease of capturing photos.", "isCommentAutoGenerated" : true }, - "Enable Camera" : { - "comment" : "Text on the action button for enabling camera permission.", - "isCommentAutoGenerated" : true - }, "Enable Center Stage" : { "comment" : "An accessibility label for the toggle that enables the \"Center Stage\" feature.", "extractionState" : "stale", @@ -1154,14 +1148,6 @@ } } }, - "Enable Microphone" : { - "comment" : "Title for the button that enables microphone access.", - "isCommentAutoGenerated" : true - }, - "Enable Photos" : { - "comment" : "Title for the button that enables photo library access in the onboarding.", - "isCommentAutoGenerated" : true - }, "Enable Ring Light" : { "comment" : "Title of a toggle in the Settings view that allows the user to enable or disable the ring light overlay.", "isCommentAutoGenerated" : true, @@ -1810,6 +1796,14 @@ } } }, + "Onboarding Reset" : { + "comment" : "The title of an alert that confirms the onboarding state has been reset.", + "isCommentAutoGenerated" : true + }, + "Onboarding will show again when you restart the app." : { + "comment" : "A message displayed in an alert when the \"Reset Onboarding\" button is tapped.", + "isCommentAutoGenerated" : true + }, "One Time" : { "comment" : "A description of a one-time purchase option.", "isCommentAutoGenerated" : true @@ -1960,6 +1954,14 @@ } } }, + "Plans are currently unavailable. Please try again." : { + "comment" : "A message displayed when the user is unable to load available subscription plans.", + "isCommentAutoGenerated" : true + }, + "Plans are unavailable right now. Please try again." : { + "comment" : "An error message displayed when the user tries to purchase a plan but there are no available plans.", + "isCommentAutoGenerated" : true + }, "Please select a plan." : { "comment" : "Error message displayed when the user tries to purchase a package but hasn't selected one.", "isCommentAutoGenerated" : true @@ -2051,6 +2053,10 @@ "comment" : "An accessibility label for the section of the settings view that displays that their Pro subscription is active.", "isCommentAutoGenerated" : true }, + "Processing..." : { + "comment" : "A label displayed while a purchase is being processed.", + "isCommentAutoGenerated" : true + }, "Purchase Error" : { "comment" : "The title of an alert that appears when there is an error during a purchase process.", "isCommentAutoGenerated" : true @@ -2127,6 +2133,10 @@ } } }, + "Reset Onboarding" : { + "comment" : "A button label that resets the onboarding state and triggers the onboarding flow again on the next app launch.", + "isCommentAutoGenerated" : true + }, "Restore Purchases" : { "comment" : "A button that restores purchases.", "isCommentAutoGenerated" : true, @@ -2200,6 +2210,10 @@ } } }, + "Retry" : { + "comment" : "A button label that attempts to reload available products when the initial load fails.", + "isCommentAutoGenerated" : true + }, "Ring Light" : { "localizations" : { "es-MX" : { @@ -2777,6 +2791,10 @@ } } }, + "Show onboarding flow on next app launch" : { + "comment" : "A description of what happens when the \"Reset Onboarding\" button is pressed.", + "isCommentAutoGenerated" : true + }, "Shows a grid overlay to help compose your shot" : { "comment" : "A toggle that enables or disables the rule of thirds grid overlay in the camera view.", "isCommentAutoGenerated" : true, diff --git a/docs/APP_REVIEW_CHECKLIST.md b/docs/APP_REVIEW_CHECKLIST.md index a6501b3..a9b0f73 100644 --- a/docs/APP_REVIEW_CHECKLIST.md +++ b/docs/APP_REVIEW_CHECKLIST.md @@ -1,6 +1,6 @@ # App Review Rejection Checklist -Last updated: 2026-02-12 +Last updated: 2026-02-14 ## Current Status @@ -11,33 +11,40 @@ Last updated: 2026-02-12 - [x] Verified app still builds after paywall fix. - Debug build: success - Release build: success +- [x] Resolved UITest build blocker (`Multiple commands produce ... Selfie_Cam.swiftmodule`). + - File: `SelfieCam/SelfieCam.xcodeproj/project.pbxproj` + - Fix: set test target `PRODUCT_NAME = "$(TARGET_NAME)"` and app target `PRODUCT_MODULE_NAME = SelfieCam`. + - Validation: `xcodebuild ... build-for-testing` on iPad Air 11-inch (M3), iOS 26.2 succeeded. ## Guideline 2.1 - App Completeness (IAP not submitted) -- [ ] In App Store Connect, ensure all IAPs are fully configured (metadata, pricing, localization). -- [ ] Upload required App Review screenshot for each IAP/subscription. +- [x] In App Store Connect, ensure all IAPs are fully configured (metadata, pricing, localization). + - Pro Monthly, Pro Yearly (subscriptions), Pro Lifetime (non-consumable) all Ready to Submit. + - Product ID for lifetime: `com.mbrucedogs.SelfieCam.pro.lifetime.purchase` +- [x] Upload required App Review screenshot for each IAP/subscription. - [ ] Submit all IAP products for review with the app version. - [ ] Upload a new app binary and submit app + IAPs together. ## Guideline 2.1 - App Completeness (IAP bug: Continue unresponsive) - [x] Code-side paywall resiliency fix implemented (no silent button failure). -- [ ] Run sandbox purchase tests on iPad form factor before resubmission. +- [x] Run sandbox purchase tests on iPad form factor before resubmission. - Review device reported by Apple: iPad Air 11-inch (M3), iPadOS 26.2.1 -- [ ] Confirm Paid Apps Agreement is active. +- [x] Confirm Paid Apps Agreement is active. - Location: App Store Connect -> Agreements, Tax, and Banking ## Guideline 1.5 - Safety (Support URL) -- [ ] Update Support URL destination so it clearly provides support contact/help content. +- [x] Update Support URL destination so it clearly provides support contact/help content. - Current URL: `https://topdoglabs.com/support` -- [ ] Ensure support page includes: +- [x] Ensure support page includes: - Contact method (email or form) - App name(s) supported - Expected response time - Troubleshooting/help info - Link to privacy policy -- [ ] Re-verify URL loads reliably in browser without requiring app login. +- [x] Re-verify URL loads reliably in browser without requiring app login. + - Verified on 2026-02-12 via direct HTTP fetch: static HTML now includes support email, response time, privacy link, app-specific subject options, and contact details. ## Guideline 5.1.1 - Privacy (Permission Request Button Wording) @@ -51,12 +58,18 @@ Issue reported: pre-permission custom screen uses "Enable Camera" style button t - Existing localized `"Continue"` key is already present for supported locales (`en`, `es-MX`, `fr-CA`), so no new key entries were required. - [x] Update UI tests that currently look for old button labels. - File: `SelfieCamUITests/SelfieCamUITests.swift` -- [ ] Verify onboarding permission flow still works for camera/microphone/photo library. - - Note: attempted UITest validation is currently blocked by an existing project test-build issue (`Multiple commands produce ... Selfie_Cam.swiftmodule`). +- [x] Verify onboarding permission flow still works for camera/microphone/photo library. + - Validation run on 2026-02-14: + - `xcodebuild -project SelfieCam/SelfieCam.xcodeproj -scheme SelfieCam -destination 'platform=iOS Simulator,name=iPad Air 11-inch (M3),OS=26.2' test -only-testing:SelfieCamUITests/SelfieCamUITests/testAppStorePortraitScreenshots` + - Result: `** TEST SUCCEEDED **` ## Resubmission Checklist -- [ ] Increment build number and archive a new build. +- [x] Increment build number and archive a new build. + - Build number: `2` (`CURRENT_PROJECT_VERSION = 2`) + - Archive command: + - `xcodebuild -project SelfieCam/SelfieCam.xcodeproj -scheme SelfieCam -configuration Release -destination 'generic/platform=iOS' -archivePath /tmp/SelfieCam_2026-02-14.xcarchive CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YES archive` + - Result: `** ARCHIVE SUCCEEDED **` - [ ] Upload new build to App Store Connect. - [ ] Attach submitted IAPs to the app version. - [ ] Add App Review Notes summarizing fixes: