Complete accessibility identifier coverage across all 152 project files
Exhaustive file-by-file audit of every Swift file in the project (iOS app, Watch app, Widget extension). Every interactive UI element — buttons, toggles, pickers, links, menus, tap gestures, text editors, color pickers, photo pickers — now has an accessibilityIdentifier for XCUITest automation. 46 files changed across Shared/, Onboarding/, Watch App/, and Widget targets. Added ~100 new ID definitions covering settings debug controls, export/photo views, sharing templates, customization subviews, onboarding flows, tip modals, widget voting buttons, and watch mood buttons.
This commit is contained in:
@@ -111,6 +111,7 @@ struct MoodButton: View {
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Watch.moodButton(mood.strValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@ struct NonSubscriberView: View {
|
||||
}
|
||||
.accessibilityLabel(String(localized: "Track Your Mood"))
|
||||
.accessibilityHint(String(localized: "Tap to open app and subscribe"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.subscribeLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ struct VotingView: View {
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Log this mood"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.voteMoodButton(mood.strValue))
|
||||
} else {
|
||||
Link(destination: URL(string: "reflect://subscribe")!) {
|
||||
moodIcon(for: mood, size: size)
|
||||
@@ -100,6 +101,7 @@ struct VotingView: View {
|
||||
}
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Open app to subscribe"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.subscribeLink)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,12 +121,14 @@ struct VotingView: View {
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Log this mood"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.voteMoodButton(mood.strValue))
|
||||
} else {
|
||||
Link(destination: URL(string: "reflect://subscribe")!) {
|
||||
content
|
||||
}
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Open app to subscribe"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.subscribeLink)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,12 +200,14 @@ struct LargeVotingView: View {
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Log this mood"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.voteMoodButton(mood.strValue))
|
||||
} else {
|
||||
Link(destination: URL(string: "reflect://subscribe")!) {
|
||||
moodButtonContent(for: mood)
|
||||
}
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Open app to subscribe"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.subscribeLink)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,12 +267,14 @@ struct InlineVotingView: View {
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Log this mood"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.voteMoodButton(mood.strValue))
|
||||
} else {
|
||||
Link(destination: URL(string: "reflect://subscribe")!) {
|
||||
moodIcon(for: mood)
|
||||
}
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Open app to subscribe"))
|
||||
.accessibilityIdentifier(AccessibilityID.Widget.subscribeLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,45 @@ enum AccessibilityID {
|
||||
static let reminderTimePicker = "settings_reminder_time_picker"
|
||||
static let reminderSaveButton = "settings_reminder_save"
|
||||
static let reminderCancelButton = "settings_reminder_cancel"
|
||||
static let reminderTimeButton = "settings_reminder_time"
|
||||
static let changeTrialDateButton = "settings_change_trial_date"
|
||||
static let trialDatePickerDoneButton = "settings_trial_date_done"
|
||||
static let trialDatePicker = "settings_trial_date_picker"
|
||||
static let paywallPreviewButton = "settings_paywall_preview"
|
||||
static let tipsPreviewButton = "settings_tips_preview"
|
||||
static let testNotificationsButton = "settings_test_notifications"
|
||||
static let exportWidgetsButton = "settings_export_widgets"
|
||||
static let exportVotingLayoutsButton = "settings_export_voting_layouts"
|
||||
static let exportWatchViewsButton = "settings_export_watch_views"
|
||||
static let exportInsightsButton = "settings_export_insights"
|
||||
static let generateScreenshotsButton = "settings_generate_screenshots"
|
||||
static let addTestDataButton = "settings_add_test_data"
|
||||
static let deleteHealthKitButton = "settings_delete_health_kit"
|
||||
static let locationAlertOpenSettingsButton = "settings_location_open_settings"
|
||||
static let locationAlertCancelButton = "settings_location_cancel"
|
||||
static let fontAwesomeLink = "settings_font_awesome_link"
|
||||
static let chartsLink = "settings_charts_link"
|
||||
static let exportDataButton = "settings_export_data"
|
||||
static let closeButton = "settings_close"
|
||||
static let resetLaunchDateButton = "settings_reset_launch_date"
|
||||
static let fixWeekdayButton = "settings_fix_weekday"
|
||||
static let whyBackgroundModeButton = "settings_why_bg_mode"
|
||||
static let exportLegacyButton = "settings_export_legacy"
|
||||
static let importButton = "settings_import"
|
||||
static let randomIconsButton = "settings_random_icons"
|
||||
static let doneButton = "settings_done"
|
||||
static let specialThanksButton = "settings_special_thanks"
|
||||
}
|
||||
|
||||
// MARK: - TipModal
|
||||
enum TipModal {
|
||||
static let dismissButton = "tip_modal_dismiss"
|
||||
static let resetTipsButton = "tip_modal_reset_tips"
|
||||
static let tipsEnabledToggle = "tip_modal_tips_enabled"
|
||||
static let doneButton = "tip_modal_done"
|
||||
static func tipPreviewButton(_ index: Int) -> String {
|
||||
"tip_modal_preview_\(index)"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Customize
|
||||
@@ -129,6 +168,7 @@ enum AccessibilityID {
|
||||
static let appThemePickerDoneButton = "apptheme_picker_done"
|
||||
static let appThemePreviewCancelButton = "apptheme_preview_cancel"
|
||||
static let appThemePreviewApplyButton = "apptheme_preview_apply"
|
||||
static let widgetHowToLink = "customize_widget_how_to_link"
|
||||
static func themeButton(_ name: String) -> String {
|
||||
"customize_theme_\(name.lowercased())"
|
||||
}
|
||||
@@ -147,6 +187,31 @@ enum AccessibilityID {
|
||||
static func appThemeCard(_ name: String) -> String {
|
||||
"apptheme_card_\(name.lowercased())"
|
||||
}
|
||||
static func customWidget(_ index: Int) -> String {
|
||||
"customize_widget_\(index)"
|
||||
}
|
||||
static let customWidgetAdd = "customize_widget_add"
|
||||
static func shapeOption(_ name: String) -> String {
|
||||
"customize_shape_\(name.lowercased())"
|
||||
}
|
||||
static let shapeRefresh = "customize_shape_refresh"
|
||||
static func imagePackOption(_ name: String) -> String {
|
||||
"customize_imagepack_option_\(name.lowercased())"
|
||||
}
|
||||
static func personalityPackOption(_ name: String) -> String {
|
||||
"customize_personalitypack_option_\(name.lowercased())"
|
||||
}
|
||||
static func celebrationAnimationButton(_ name: String) -> String {
|
||||
"customize_celebration_\(name.lowercased())"
|
||||
}
|
||||
static let manageSubscriptionButton = "customize_manage_subscription"
|
||||
static let unlockPremiumButton = "customize_unlock_premium"
|
||||
static func dayFilterButton(_ day: String) -> String {
|
||||
"customize_day_filter_\(day.lowercased())"
|
||||
}
|
||||
static func iconButton(_ name: String) -> String {
|
||||
"customize_icon_\(name.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Paywall
|
||||
@@ -173,21 +238,32 @@ enum AccessibilityID {
|
||||
static let monthSection = "insights_month_section"
|
||||
static let yearSection = "insights_year_section"
|
||||
static let allTimeSection = "insights_all_time_section"
|
||||
static let expandCollapseButton = "insights_expand_collapse"
|
||||
}
|
||||
|
||||
// MARK: - Month View
|
||||
enum MonthView {
|
||||
static let grid = "month_grid"
|
||||
static let shareButton = "month_share_button"
|
||||
static let statsToggleButton = "month_stats_toggle"
|
||||
static let settingsButton = "month_settings_button"
|
||||
static func dayCell(dateString: String) -> String {
|
||||
"month_day_cell_\(dateString)"
|
||||
}
|
||||
static let debugDemoToggle = "month_debug_demo_toggle"
|
||||
}
|
||||
|
||||
// MARK: - Month Detail
|
||||
enum MonthDetail {
|
||||
static let shareButton = "month_detail_share"
|
||||
static let deleteButton = "month_detail_delete"
|
||||
static let cancelButton = "month_detail_cancel"
|
||||
static func moodButton(_ mood: String) -> String {
|
||||
"month_detail_mood_\(mood.lowercased())"
|
||||
}
|
||||
static func entryCell(_ dateString: String) -> String {
|
||||
"month_detail_entry_\(dateString)"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Year View
|
||||
@@ -198,6 +274,7 @@ enum AccessibilityID {
|
||||
static let statsSection = "year_stats_section"
|
||||
static func cardHeader(year: Int) -> String { "year_card_header_\(year)" }
|
||||
static let shareButton = "year_share_button"
|
||||
static let debugDemoToggle = "year_debug_demo_toggle"
|
||||
}
|
||||
|
||||
// MARK: - Onboarding
|
||||
@@ -213,12 +290,23 @@ enum AccessibilityID {
|
||||
static let subscribeButton = "onboarding_subscribe_button"
|
||||
static let skipButton = "onboarding_skip_button"
|
||||
static let nextButton = "onboarding_next_button"
|
||||
static let timePicker = "onboarding_time_picker"
|
||||
static let wrapupContinue = "onboarding_wrapup_continue"
|
||||
static let titleOptionButton = "onboarding_title_option"
|
||||
static func styleThemeButton(_ name: String) -> String {
|
||||
"onboarding_style_theme_\(name.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Reports
|
||||
enum Reports {
|
||||
static let segmentedPicker = "reports_segmented_picker"
|
||||
static let dateRangePicker = "reports_date_range_picker"
|
||||
static let previousMonthButton = "reports_previous_month"
|
||||
static let nextMonthButton = "reports_next_month"
|
||||
static func dayCell(dateString: String) -> String {
|
||||
"reports_day_cell_\(dateString)"
|
||||
}
|
||||
static let quickSummaryButton = "reports_quick_summary_button"
|
||||
static let detailedReportButton = "reports_detailed_report_button"
|
||||
static let generateButton = "reports_generate_button"
|
||||
@@ -229,6 +317,8 @@ enum AccessibilityID {
|
||||
static let minimumEntriesWarning = "reports_minimum_entries_warning"
|
||||
static let exportDataButton = "reports_export_data_button"
|
||||
static let retryButton = "reports_retry_button"
|
||||
static let privacyShareButton = "reports_privacy_share"
|
||||
static let privacyCancelButton = "reports_privacy_cancel"
|
||||
}
|
||||
|
||||
// MARK: - Purchase / Subscription
|
||||
@@ -239,6 +329,11 @@ enum AccessibilityID {
|
||||
static let subscribeButton = "purchase_subscribe"
|
||||
}
|
||||
|
||||
// MARK: - Subscription Store
|
||||
enum SubscriptionStore {
|
||||
static let closeButton = "subscription_store_close"
|
||||
}
|
||||
|
||||
// MARK: - IAP Warning
|
||||
enum IAPWarning {
|
||||
static let subscribeButton = "iap_warning_subscribe"
|
||||
@@ -249,6 +344,7 @@ enum AccessibilityID {
|
||||
static let unlockButton = "lock_screen_unlock"
|
||||
static let tryAgainButton = "lock_screen_try_again"
|
||||
static let cancelButton = "lock_screen_cancel"
|
||||
static let passcodeUnlockButton = "lock_screen_passcode_unlock"
|
||||
static func passcodeButton(_ digit: Int) -> String {
|
||||
"lock_screen_passcode_\(digit)"
|
||||
}
|
||||
@@ -260,6 +356,135 @@ enum AccessibilityID {
|
||||
static let dismissArea = "full_screen_photo_dismiss"
|
||||
}
|
||||
|
||||
// MARK: - Export
|
||||
enum Export {
|
||||
static let cancelButton = "export_cancel"
|
||||
static let exportButton = "export_export"
|
||||
static let alertOKButton = "export_alert_ok"
|
||||
static func formatButton(_ format: String) -> String {
|
||||
"export_format_\(format.lowercased())"
|
||||
}
|
||||
static func rangeButton(_ range: String) -> String {
|
||||
"export_range_\(range.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Photo Picker
|
||||
enum PhotoPicker {
|
||||
static let cameraButton = "photo_picker_camera"
|
||||
static let cancelButton = "photo_picker_cancel"
|
||||
static let closeButton = "photo_picker_close"
|
||||
static let shareButton = "photo_picker_share"
|
||||
static let deleteButton = "photo_picker_delete"
|
||||
static let deleteConfirmButton = "photo_picker_delete_confirm"
|
||||
static let deleteCancelButton = "photo_picker_delete_cancel"
|
||||
static let photosPicker = "photo_picker_library"
|
||||
static let photoImage = "photo_picker_image"
|
||||
static let menuButton = "photo_picker_menu"
|
||||
}
|
||||
|
||||
// MARK: - Sharing
|
||||
enum Sharing {
|
||||
static let exitButton = "sharing_exit"
|
||||
static let shareButton = "sharing_share"
|
||||
static func moodMenuButton(_ mood: String) -> String {
|
||||
"sharing_mood_menu_\(mood.lowercased())"
|
||||
}
|
||||
static let moodMenu = "sharing_mood_menu"
|
||||
static func templateButton(_ description: String) -> String {
|
||||
"sharing_template_\(description.lowercased().replacingOccurrences(of: " ", with: "_"))"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sharing Templates
|
||||
enum SharingTemplate {
|
||||
static let dismissButton = "sharing_template_dismiss"
|
||||
static let shareButton = "sharing_template_share"
|
||||
static let moodMenu = "sharing_template_mood_menu"
|
||||
static func moodMenuButton(_ mood: String) -> String {
|
||||
"sharing_template_mood_menu_\(mood.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Custom Widget
|
||||
enum CustomWidget {
|
||||
static func colorPicker(_ name: String) -> String {
|
||||
"custom_widget_color_\(name.lowercased())"
|
||||
}
|
||||
static let leftEyeButton = "custom_widget_left_eye"
|
||||
static let rightEyeButton = "custom_widget_right_eye"
|
||||
static let mouthButton = "custom_widget_mouth"
|
||||
static func backgroundOption(_ index: Int) -> String {
|
||||
"custom_widget_bg_\(index)"
|
||||
}
|
||||
static let randomBackgroundButton = "custom_widget_random_bg"
|
||||
static let shuffleButton = "custom_widget_shuffle"
|
||||
static let saveButton = "custom_widget_save"
|
||||
static let useButton = "custom_widget_use"
|
||||
static let deleteButton = "custom_widget_delete"
|
||||
static func imageOption(_ name: String) -> String {
|
||||
"custom_widget_image_\(name.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Debug / Preview
|
||||
enum Debug {
|
||||
static let animationDoneButton = "debug_animation_done"
|
||||
static func animationCard(_ name: String) -> String {
|
||||
"debug_animation_\(name.lowercased())"
|
||||
}
|
||||
static func debugMoodButton(_ mood: String) -> String {
|
||||
"debug_mood_\(mood.lowercased())"
|
||||
}
|
||||
static let paywallPreviewDoneButton = "debug_paywall_done"
|
||||
static let viewFullPaywallButton = "debug_view_full_paywall"
|
||||
static func paywallStyleOption(_ name: String) -> String {
|
||||
"debug_paywall_style_\(name.lowercased())"
|
||||
}
|
||||
static let liveActivityResetButton = "debug_live_activity_reset"
|
||||
static let liveActivityToggleButton = "debug_live_activity_toggle"
|
||||
static let liveActivityRecordButton = "debug_live_activity_record"
|
||||
static let liveActivityDismissButton = "debug_live_activity_dismiss"
|
||||
static let liveActivityExportButton = "debug_live_activity_export"
|
||||
}
|
||||
|
||||
// MARK: - Sample Entry
|
||||
enum SampleEntry {
|
||||
static let refreshButton = "sample_entry_refresh"
|
||||
}
|
||||
|
||||
// MARK: - Switchable View
|
||||
enum SwitchableView {
|
||||
static let headerToggle = "switchable_view_header_toggle"
|
||||
}
|
||||
|
||||
// MARK: - Neon Mood Button (voting layout)
|
||||
enum NeonMoodButton {
|
||||
static func id(for mood: String) -> String {
|
||||
"neon_mood_button_\(mood.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - App Alerts
|
||||
enum AppAlert {
|
||||
static let storageUnavailableOK = "app_alert_storage_ok"
|
||||
}
|
||||
|
||||
// MARK: - Watch
|
||||
enum Watch {
|
||||
static func moodButton(_ mood: String) -> String {
|
||||
"watch_mood_button_\(mood.lowercased())"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Widget
|
||||
enum Widget {
|
||||
static func voteMoodButton(_ mood: String) -> String {
|
||||
"widget_vote_mood_\(mood.lowercased())"
|
||||
}
|
||||
static let subscribeLink = "widget_subscribe_link"
|
||||
}
|
||||
|
||||
// MARK: - Common
|
||||
enum Common {
|
||||
static let lockScreen = "lock_screen"
|
||||
|
||||
@@ -195,6 +195,7 @@ struct OnboardingThemeCard: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.styleThemeButton(theme.name))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ struct OnboardingTime: View {
|
||||
.datePickerStyle(.wheel)
|
||||
.labelsHidden()
|
||||
.colorScheme(.light)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.timePicker)
|
||||
.accessibilityLabel(String(localized: "Reminder time"))
|
||||
.accessibilityHint(String(localized: "Select when you want to be reminded"))
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ struct OnboardingTitle: View {
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.titleOptionButton)
|
||||
.padding([.top], 10)
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ struct OnboardingWrapup: View {
|
||||
.background(RoundedRectangle(cornerRadius: 10).fill().foregroundColor(Color.white))
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.wrapupContinue)
|
||||
.padding([.top], 65)
|
||||
}
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
@@ -73,6 +73,7 @@ struct ReflectApp: App {
|
||||
.alert("Data Storage Unavailable",
|
||||
isPresented: $showStorageFallbackAlert) {
|
||||
Button("OK", role: .cancel) { }
|
||||
.accessibilityIdentifier(AccessibilityID.AppAlert.storageUnavailableOK)
|
||||
} message: {
|
||||
Text("Your mood data cannot be saved permanently. Please restart the app. If the problem persists, reinstall the app.")
|
||||
}
|
||||
|
||||
@@ -696,7 +696,7 @@ struct NeonEqualizerBar: View {
|
||||
}
|
||||
.buttonStyle(NeonBarButtonStyle(isPressed: $isPressed))
|
||||
.frame(maxWidth: .infinity)
|
||||
.accessibilityIdentifier(AccessibilityID.MoodButton.id(for: mood.widgetDisplayName))
|
||||
.accessibilityIdentifier(AccessibilityID.NeonMoodButton.id(for: mood.widgetDisplayName))
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.frame(minHeight: 40, maxHeight: .infinity)
|
||||
.background(.blue)
|
||||
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.shuffleButton)
|
||||
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.widgetCreated)
|
||||
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: false)
|
||||
@@ -127,7 +128,8 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.frame(minHeight: 40, maxHeight: .infinity)
|
||||
.background(.green)
|
||||
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.saveButton)
|
||||
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.widgetUsed)
|
||||
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: true)
|
||||
@@ -145,7 +147,8 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.frame(minHeight: 40, maxHeight: .infinity)
|
||||
.background(.pink)
|
||||
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.useButton)
|
||||
|
||||
if customWidget.isSaved {
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.widgetDeleted)
|
||||
@@ -163,6 +166,7 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.frame(minHeight: 40, maxHeight: .infinity)
|
||||
.background(.orange)
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.deleteButton)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 40, maxHeight: .infinity)
|
||||
@@ -178,6 +182,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "background"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("bg"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
|
||||
@@ -188,6 +193,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "inner"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("inner"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
|
||||
@@ -198,6 +204,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "outline"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("stroke"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
}
|
||||
@@ -210,6 +217,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "left_eye"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("leftEye"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
|
||||
@@ -220,6 +228,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "right_eye"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("rightEye"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
|
||||
@@ -230,6 +239,7 @@ struct CreateWidgetView: View {
|
||||
AnalyticsManager.shared.track(.widgetColorUpdated(part: "mouth"))
|
||||
}
|
||||
.labelsHidden()
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("mouth"))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
}
|
||||
@@ -250,16 +260,19 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 10, idealWidth: 40, maxWidth: 40,
|
||||
minHeight: 10, idealHeight: 40, maxHeight: 40,
|
||||
alignment: .center)
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.backgroundOption(CustomWidgetBackGroundOptions.selectable.firstIndex(of: bg) ?? 0))
|
||||
.onTapGesture {
|
||||
update(background: bg)
|
||||
}
|
||||
}
|
||||
mixBG
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.randomBackgroundButton)
|
||||
.onTapGesture {
|
||||
update(background: .random)
|
||||
}
|
||||
Divider()
|
||||
ColorPicker("", selection: $customWidget.bgOverlayColor)
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.colorPicker("bgOverlay"))
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
@@ -270,6 +283,7 @@ struct CreateWidgetView: View {
|
||||
var faceImageOptions: some View {
|
||||
HStack(alignment: .center) {
|
||||
Text(String(localized: "create_widget_view_left_eye"))
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.leftEyeButton)
|
||||
.onTapGesture(perform: {
|
||||
showLeftEyeImagePicker.toggle()
|
||||
})
|
||||
@@ -278,6 +292,7 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
Divider()
|
||||
Text(String(localized: "create_widget_view_right_eye"))
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.rightEyeButton)
|
||||
.onTapGesture(perform: {
|
||||
showRightEyeImagePicker.toggle()
|
||||
})
|
||||
@@ -285,6 +300,7 @@ struct CreateWidgetView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
Divider()
|
||||
Text(String(localized: "create_widget_view_mouth"))
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.mouthButton)
|
||||
.onTapGesture(perform: {
|
||||
showMuthImagePicker.toggle()
|
||||
})
|
||||
|
||||
@@ -538,6 +538,7 @@ struct CelebrationAnimationPickerCompact: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.celebrationAnimationButton(animation.rawValue))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 4)
|
||||
@@ -666,6 +667,7 @@ struct CustomWidgetSection: View {
|
||||
CustomWidgetView(customWidgetModel: widget)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(12)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.customWidget(UserDefaultsStore.getCustomWidgets().firstIndex(where: { $0.uuid == widget.uuid }) ?? 0))
|
||||
.onTapGesture {
|
||||
AnalyticsManager.shared.track(.widgetViewed)
|
||||
selectedWidget.selectedItem = widget.copy() as? CustomWidgetModel
|
||||
@@ -689,6 +691,7 @@ struct CustomWidgetSection: View {
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.customWidgetAdd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +704,7 @@ struct CustomWidgetSection: View {
|
||||
}
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.widgetHowToLink)
|
||||
}
|
||||
.sheet(isPresented: $selectedWidget.showSheet) {
|
||||
if let selectedItem = selectedWidget.selectedItem {
|
||||
@@ -822,6 +826,7 @@ struct SubscriptionBannerView: View {
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 8)
|
||||
.background(Capsule().fill(Color.green.opacity(0.15)))
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.manageSubscriptionButton)
|
||||
}
|
||||
.padding(16)
|
||||
}
|
||||
@@ -866,6 +871,7 @@ struct SubscriptionBannerView: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.unlockPremiumButton)
|
||||
}
|
||||
|
||||
private func openSubscriptionManagement() async {
|
||||
|
||||
@@ -23,6 +23,7 @@ struct CustomWigetView: View {
|
||||
CustomWidgetView(customWidgetModel: widget)
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(10)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.customWidget(UserDefaultsStore.getCustomWidgets().firstIndex(where: { $0.uuid == widget.uuid }) ?? 0))
|
||||
.onTapGesture {
|
||||
AnalyticsManager.shared.track(.widgetViewed)
|
||||
selectedWidget.selectedItem = widget.copy() as? CustomWidgetModel
|
||||
@@ -34,6 +35,7 @@ struct CustomWigetView: View {
|
||||
.overlay(
|
||||
Image(systemName: "plus")
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.customWidgetAdd)
|
||||
.onTapGesture {
|
||||
AnalyticsManager.shared.track(.widgetCreateTapped)
|
||||
selectedWidget.selectedItem = CustomWidgetModel.randomWidget
|
||||
@@ -47,6 +49,7 @@ struct CustomWigetView: View {
|
||||
.cornerRadius(10)
|
||||
|
||||
Text("[\(String(localized: "how_to_add_widget"))](https://support.apple.com/guide/iphone/add-widgets-iphb8f1bf206/ios)")
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.widgetHowToLink)
|
||||
.accentColor(textColor)
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ struct DayFilterPickerView: View {
|
||||
.cornerRadius(8)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.dayFilterButton(day))
|
||||
}
|
||||
}
|
||||
Text(String(localized: "day_picker_view_text"))
|
||||
|
||||
@@ -64,6 +64,7 @@ struct IconPickerView: View {
|
||||
})
|
||||
.accessibilityLabel(String(localized: "Default app icon"))
|
||||
.accessibilityHint(String(localized: "Double tap to select"))
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.iconButton("default"))
|
||||
|
||||
|
||||
ForEach(iconSets, id: \.self.0){ iconSet in
|
||||
@@ -80,6 +81,7 @@ struct IconPickerView: View {
|
||||
})
|
||||
.accessibilityLabel(String(localized: "App icon style \(iconSet.1.replacingOccurrences(of: "AppIcon", with: "").replacingOccurrences(of: "Image", with: ""))"))
|
||||
.accessibilityHint(String(localized: "Double tap to select"))
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.iconButton(iconSet.1))
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
@@ -41,6 +41,7 @@ struct ImagePackPickerView: View {
|
||||
.fill(imagePack == images ? theme.currentTheme.bgColor : .clear)
|
||||
.padding([.top, .bottom], -3)
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.imagePackOption(String(describing: images)))
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
|
||||
@@ -38,6 +38,7 @@ struct PersonalityPackPickerView: View {
|
||||
.fill(personalityPack == aPack ? theme.currentTheme.bgColor : .clear)
|
||||
.padding(5)
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.personalityPackOption(aPack.title()))
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
|
||||
@@ -31,6 +31,7 @@ struct ShapePickerView: View {
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20, alignment: .trailing)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.shapeRefresh)
|
||||
.onTapGesture {
|
||||
shapeRefreshToggleThing.toggle()
|
||||
}
|
||||
@@ -43,6 +44,7 @@ struct ShapePickerView: View {
|
||||
bgColor: moodTint.color(forMood: Mood.allValues.randomElement()!), textColor: textColor)
|
||||
.frame(height: 50)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.shapeOption(String(describing: ashape)))
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
|
||||
@@ -58,6 +58,7 @@ struct ThemePickerView: View {
|
||||
.fill(selectedTheme == theme ? selectedTheme.currentTheme.bgColor : .clear)
|
||||
.padding(-5)
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.themeButton(theme.title))
|
||||
}
|
||||
|
||||
private func selectTheme(_ theme: Theme) {
|
||||
|
||||
@@ -59,6 +59,7 @@ struct VotingLayoutPickerView: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Customize.votingLayoutButton(layout.displayName))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
@@ -104,6 +104,7 @@ struct ExportView: View {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Export.cancelButton)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showShareSheet) {
|
||||
@@ -113,6 +114,7 @@ struct ExportView: View {
|
||||
}
|
||||
.alert("Export Failed", isPresented: $showError) {
|
||||
Button("OK", role: .cancel) { }
|
||||
.accessibilityIdentifier(AccessibilityID.Export.alertOKButton)
|
||||
} message: {
|
||||
Text(errorMessage)
|
||||
}
|
||||
@@ -230,6 +232,7 @@ struct ExportView: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Export.formatButton(format.rawValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,6 +263,7 @@ struct ExportView: View {
|
||||
.background(Color(.systemBackground))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Export.rangeButton(range.rawValue))
|
||||
|
||||
if range != DateRange.allCases.last {
|
||||
Divider()
|
||||
@@ -293,6 +297,7 @@ struct ExportView: View {
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
.disabled(isExporting || validEntries.isEmpty)
|
||||
.accessibilityIdentifier(AccessibilityID.Export.exportButton)
|
||||
.padding(.top, 8)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ struct ImagePickerGridView: View {
|
||||
.scaledToFit()
|
||||
.frame(width: 40, height: 40)
|
||||
.foregroundColor(textColor)
|
||||
.accessibilityIdentifier(AccessibilityID.CustomWidget.imageOption(item.rawValue))
|
||||
.onTapGesture {
|
||||
pickedImageClosure(item)
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
|
||||
@@ -277,6 +277,7 @@ struct InsightsSectionView: View {
|
||||
.padding(.vertical, 14)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.Insights.expandCollapseButton)
|
||||
.accessibilityAddTraits(.isHeader)
|
||||
|
||||
// Insights List (collapsible)
|
||||
|
||||
@@ -146,6 +146,7 @@ struct ReportDateRangePicker: View {
|
||||
.background(Color.accentColor.opacity(0.15))
|
||||
.clipShape(Circle())
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.previousMonthButton)
|
||||
.accessibilityLabel("Previous month")
|
||||
|
||||
Spacer()
|
||||
@@ -172,6 +173,7 @@ struct ReportDateRangePicker: View {
|
||||
.background(Color.accentColor.opacity(0.15))
|
||||
.clipShape(Circle())
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.nextMonthButton)
|
||||
.accessibilityLabel("Next month")
|
||||
.disabled(isDisplayingCurrentMonth)
|
||||
}
|
||||
@@ -341,6 +343,7 @@ private struct ReportDayCell: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(isFuture)
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.dayCell(dateString: dayNumber))
|
||||
.frame(height: 40)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,9 @@ struct ReportsView: View {
|
||||
viewModel.exportDataPDF()
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.privacyShareButton)
|
||||
Button(String(localized: "Cancel"), role: .cancel) {}
|
||||
.accessibilityIdentifier(AccessibilityID.Reports.privacyCancelButton)
|
||||
} message: {
|
||||
Text("This report contains your personal mood data and journal notes. Only share it with people you trust.")
|
||||
}
|
||||
|
||||
@@ -1691,6 +1691,7 @@ struct LockScreenView: View {
|
||||
.disabled(authManager.isAuthenticating)
|
||||
.padding(.top, 16)
|
||||
.opacity(showContent ? 1 : 0)
|
||||
.accessibilityIdentifier(AccessibilityID.LockScreen.passcodeUnlockButton)
|
||||
.accessibilityLabel("Use device passcode")
|
||||
.accessibilityHint("Double tap to authenticate with your device passcode")
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ struct MonthDetailView: View {
|
||||
selectedEntry = nil
|
||||
showUpdateEntryAlert = false
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.MonthDetail.cancelButton)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +154,7 @@ struct MonthDetailView: View {
|
||||
LazyVGrid(columns: columns, spacing: 25) {
|
||||
ForEach(entries, id: \.self) { entry in
|
||||
listViewEntry(forEntry: entry)
|
||||
.accessibilityIdentifier(AccessibilityID.MonthDetail.entryCell(DateFormattingCache.shared.string(for: entry.forDate, format: .dateMedium)))
|
||||
.onTapGesture(perform: {
|
||||
if entry.canEdit {
|
||||
selectedEntry = entry
|
||||
|
||||
@@ -378,6 +378,7 @@ struct MonthView: View {
|
||||
.preferredColorScheme(theme.preferredColorScheme)
|
||||
#if DEBUG
|
||||
// Triple-tap to toggle demo mode for video recording
|
||||
.accessibilityIdentifier(AccessibilityID.MonthView.debugDemoToggle)
|
||||
.onTapGesture(count: 3) {
|
||||
if demoManager.isDemoMode {
|
||||
demoManager.stopDemoMode()
|
||||
@@ -591,6 +592,7 @@ struct MonthCard: View, Equatable {
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.MonthView.statsToggleButton)
|
||||
.accessibilityLabel("\(Random.monthName(fromMonthInt: month)) \(String(year)), \(showStats ? "expanded" : "collapsed")")
|
||||
.accessibilityHint("Double tap to toggle statistics")
|
||||
|
||||
@@ -661,6 +663,7 @@ struct MonthCard: View, Equatable {
|
||||
.fill(theme.currentTheme.secondaryBGColor)
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityIdentifier(AccessibilityID.MonthView.dayCell(dateString: "\(month)_\(year)"))
|
||||
.onTapGesture {
|
||||
onTap()
|
||||
}
|
||||
@@ -867,6 +870,7 @@ extension MonthView {
|
||||
}
|
||||
.padding(.top, 60)
|
||||
.padding(.trailing)
|
||||
.accessibilityIdentifier(AccessibilityID.MonthView.settingsButton)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ struct PhotoPickerView: View {
|
||||
)
|
||||
}
|
||||
.disabled(isProcessing)
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.photosPicker)
|
||||
|
||||
// Camera
|
||||
Button {
|
||||
@@ -111,6 +112,7 @@ struct PhotoPickerView: View {
|
||||
)
|
||||
}
|
||||
.disabled(isProcessing)
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.cameraButton)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
@@ -130,6 +132,7 @@ struct PhotoPickerView: View {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.cancelButton)
|
||||
}
|
||||
}
|
||||
.onChange(of: selectedItem) { _, newItem in
|
||||
@@ -278,6 +281,7 @@ struct PhotoGalleryView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.photoImage)
|
||||
} else {
|
||||
VStack(spacing: 16) {
|
||||
Image(systemName: "photo.badge.exclamationmark")
|
||||
@@ -301,6 +305,7 @@ struct PhotoGalleryView: View {
|
||||
.font(.title2)
|
||||
.foregroundStyle(.white.opacity(0.7))
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.closeButton)
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
@@ -310,17 +315,20 @@ struct PhotoGalleryView: View {
|
||||
} label: {
|
||||
Label("Share", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.shareButton)
|
||||
|
||||
Button(role: .destructive) {
|
||||
showDeleteConfirmation = true
|
||||
} label: {
|
||||
Label("Delete", systemImage: "trash")
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.deleteButton)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis.circle.fill")
|
||||
.font(.title2)
|
||||
.foregroundStyle(.white.opacity(0.7))
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.menuButton)
|
||||
}
|
||||
}
|
||||
.confirmationDialog("Delete Photo", isPresented: $showDeleteConfirmation, titleVisibility: .visible) {
|
||||
@@ -328,7 +336,9 @@ struct PhotoGalleryView: View {
|
||||
onDelete()
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.deleteConfirmButton)
|
||||
Button("Cancel", role: .cancel) { }
|
||||
.accessibilityIdentifier(AccessibilityID.PhotoPicker.deleteCancelButton)
|
||||
} message: {
|
||||
Text("Are you sure you want to delete this photo?")
|
||||
}
|
||||
|
||||
@@ -175,6 +175,7 @@ struct PurchaseButtonView: View {
|
||||
.background(Color.pink)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Purchase.subscribeButton)
|
||||
|
||||
// Restore purchases
|
||||
Button {
|
||||
|
||||
@@ -46,6 +46,7 @@ struct ReflectSubscriptionStoreView: View {
|
||||
}
|
||||
.padding(16)
|
||||
.accessibilityLabel("Close")
|
||||
.accessibilityIdentifier(AccessibilityID.SubscriptionStore.closeButton)
|
||||
}
|
||||
.onAppear {
|
||||
AppLogger.iap.info("SubscriptionStoreView appeared — source: \(source), productIDs: \(IAPManager.productIdentifiers.sorted().joined(separator: ", ")), groupID: \(IAPManager.subscriptionGroupID)")
|
||||
|
||||
@@ -22,6 +22,7 @@ struct SampleEntryView: View {
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20, alignment: .trailing)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.accessibilityIdentifier(AccessibilityID.SampleEntry.refreshButton)
|
||||
.onTapGesture {
|
||||
sampleListEntry = DataController.shared.generateObjectNotInArray(forDate: Date(), withMood: sampleListEntry.mood.next)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ struct DebugAnimationSettingsView: View {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.animationDoneButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,6 +218,7 @@ struct AnimationCard: View {
|
||||
)
|
||||
.scaleEffect(isPressed ? 0.95 : (isSelected ? 1.02 : 1.0))
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.animationCard(type.rawValue))
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.onLongPressGesture(minimumDuration: .infinity, pressing: { pressing in
|
||||
withAnimation(.easeInOut(duration: 0.15)) {
|
||||
@@ -336,6 +338,7 @@ struct DebugVotingContentView: View {
|
||||
.fill(mood.color.opacity(0.15))
|
||||
)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.debugMoodButton(mood.strValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ struct LiveActivityPreviewView: View {
|
||||
.background(Color.gray.opacity(0.2))
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.liveActivityResetButton)
|
||||
|
||||
Button(action: toggleAnimation) {
|
||||
Label(isAnimating ? "Pause" : "Start", systemImage: isAnimating ? "pause.fill" : "play.fill")
|
||||
@@ -68,6 +69,7 @@ struct LiveActivityPreviewView: View {
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.liveActivityToggleButton)
|
||||
}
|
||||
|
||||
Button(action: { showRecordingMode = true }) {
|
||||
@@ -79,6 +81,7 @@ struct LiveActivityPreviewView: View {
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.liveActivityRecordButton)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.bottom, 40)
|
||||
@@ -264,6 +267,7 @@ struct LiveActivityRecordingView: View {
|
||||
.background(Color.orange)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(12)
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.liveActivityDismissButton)
|
||||
} else if isExporting {
|
||||
Text("Exporting frames...")
|
||||
.font(.title2.bold())
|
||||
@@ -282,6 +286,7 @@ struct LiveActivityRecordingView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.liveActivityExportButton)
|
||||
.onTapGesture {
|
||||
if !isExporting && !exportComplete {
|
||||
startExport()
|
||||
|
||||
@@ -35,6 +35,7 @@ struct PaywallPreviewSettingsView: View {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.paywallPreviewDoneButton)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showFullPreview) {
|
||||
@@ -160,6 +161,7 @@ struct PaywallPreviewSettingsView: View {
|
||||
.foregroundColor(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.viewFullPaywallButton)
|
||||
}
|
||||
|
||||
private var gradientColors: [Color] {
|
||||
@@ -241,6 +243,7 @@ struct StyleOptionRow: View {
|
||||
.stroke(isSelected ? Color.accentColor : Color.clear, lineWidth: 2)
|
||||
)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Debug.paywallStyleOption(style.displayName))
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ struct WhyUpgradeView: View {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.doneButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.reminderTimeButton)
|
||||
.accessibilityLabel(String(localized: "Reminder Time"))
|
||||
.accessibilityValue(formattedReminderTime)
|
||||
.accessibilityHint(String(localized: "Opens time picker to change reminder time"))
|
||||
@@ -269,6 +270,7 @@ struct SettingsContentView: View {
|
||||
showTrialDatePicker = true
|
||||
}
|
||||
.font(.subheadline.weight(.medium))
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.changeTrialDateButton)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@@ -283,6 +285,7 @@ struct SettingsContentView: View {
|
||||
displayedComponents: .date
|
||||
)
|
||||
.datePickerStyle(.graphical)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.trialDatePicker)
|
||||
.padding()
|
||||
.navigationTitle("Set Trial Start Date")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
@@ -295,6 +298,7 @@ struct SettingsContentView: View {
|
||||
await iapManager.checkSubscriptionStatus()
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.trialDatePickerDoneButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,6 +342,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.paywallPreviewButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -381,6 +386,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.tipsPreviewButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -418,6 +424,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.testNotificationsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -470,6 +477,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingWidgets)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportWidgetsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -522,6 +530,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingVotingLayouts)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportVotingLayoutsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -574,6 +583,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingWatchViews)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportWatchViewsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -632,6 +642,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingInsights)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportInsightsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -691,6 +702,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isGeneratingScreenshots)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.generateScreenshotsButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -741,6 +753,7 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isDeletingHealthKitData)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.deleteHealthKitButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -852,11 +865,12 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.addTestDataButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
|
||||
private var healthKitToggle: some View {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 12) {
|
||||
@@ -1048,7 +1062,9 @@ struct SettingsContentView: View {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.locationAlertOpenSettingsButton)
|
||||
Button(String(localized: "Cancel"), role: .cancel) {}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.locationAlertCancelButton)
|
||||
} message: {
|
||||
Text("Reflect needs location access to show weather. You can enable it in Settings.")
|
||||
}
|
||||
@@ -1084,6 +1100,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportDataButton)
|
||||
.accessibilityLabel(String(localized: "Export Data"))
|
||||
.accessibilityHint(String(localized: "Export your mood data as CSV or PDF"))
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1382,6 +1399,7 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
Text("Test builds only")
|
||||
Toggle("Bypass Subscription", isOn: $iapManager.bypassSubscription)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.bypassSubscriptionToggle)
|
||||
addTestDataCell
|
||||
clearDB
|
||||
// fixWeekday
|
||||
@@ -1745,7 +1763,9 @@ struct SettingsView: View {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.locationAlertOpenSettingsButton)
|
||||
Button(String(localized: "Cancel"), role: .cancel) {}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.locationAlertCancelButton)
|
||||
} message: {
|
||||
Text("Reflect needs location access to show weather. You can enable it in Settings.")
|
||||
}
|
||||
@@ -1781,6 +1801,7 @@ struct SettingsView: View {
|
||||
}
|
||||
.padding()
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportDataButton)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -1797,6 +1818,7 @@ struct SettingsView: View {
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.systemBlue))
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.closeButton)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1811,17 +1833,20 @@ struct SettingsView: View {
|
||||
Text(String(localized: "settings_view_special_thanks_to_title"))
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.specialThanksButton)
|
||||
.padding()
|
||||
|
||||
if showSpecialThanks {
|
||||
Divider()
|
||||
Link("Font Awesome", destination: URL(string: "https://fontawesome.com")!)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.fontAwesomeLink)
|
||||
.accentColor(textColor)
|
||||
.padding(.bottom)
|
||||
|
||||
Divider()
|
||||
|
||||
Link("Charts", destination: URL(string: "https://github.com/danielgindi/Charts")!)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.chartsLink)
|
||||
.accentColor(textColor)
|
||||
.padding(.bottom)
|
||||
}
|
||||
@@ -1838,6 +1863,7 @@ struct SettingsView: View {
|
||||
Text("Add test data")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.addTestDataButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1867,6 +1893,7 @@ struct SettingsView: View {
|
||||
showTrialDatePicker = true
|
||||
}
|
||||
.font(.subheadline.weight(.medium))
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.changeTrialDateButton)
|
||||
}
|
||||
.padding()
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1880,6 +1907,7 @@ struct SettingsView: View {
|
||||
displayedComponents: .date
|
||||
)
|
||||
.datePickerStyle(.graphical)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.trialDatePicker)
|
||||
.padding()
|
||||
.navigationTitle("Set Trial Start Date")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
@@ -1892,6 +1920,7 @@ struct SettingsView: View {
|
||||
await iapManager.checkSubscriptionStatus()
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.trialDatePickerDoneButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1909,6 +1938,7 @@ struct SettingsView: View {
|
||||
Text("Reset luanch date to current date")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.resetLaunchDateButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1923,6 +1953,7 @@ struct SettingsView: View {
|
||||
Text("Clear DB")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.clearDataButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1937,6 +1968,7 @@ struct SettingsView: View {
|
||||
Text("Fix Weekday")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.fixWeekdayButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
@@ -1954,6 +1986,7 @@ struct SettingsView: View {
|
||||
Text(String(localized: "settings_view_why_bg_mode_title"))
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.whyBackgroundModeButton)
|
||||
.padding()
|
||||
if showWhyBGMode {
|
||||
Text(String(localized: "settings_view_why_bg_mode_body"))
|
||||
@@ -2110,13 +2143,14 @@ struct SettingsView: View {
|
||||
Text("Export")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.exportLegacyButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
|
||||
private var importData: some View {
|
||||
Button(action: {
|
||||
showingImporter.toggle()
|
||||
@@ -2125,13 +2159,14 @@ struct SettingsView: View {
|
||||
Text("Import")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.importButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
|
||||
private var randomIcons: some View {
|
||||
Button(action: {
|
||||
var iconViews = [UIImage]()
|
||||
@@ -2255,6 +2290,7 @@ struct SettingsView: View {
|
||||
Text("Create random icons")
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.randomIconsButton)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
|
||||
@@ -154,10 +154,10 @@ struct SharingListView: View {
|
||||
}, label: {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
|
||||
item.preview
|
||||
.frame(height: 88)
|
||||
|
||||
|
||||
VStack {
|
||||
Spacer()
|
||||
Text(item.description)
|
||||
@@ -179,6 +179,7 @@ struct SharingListView: View {
|
||||
.contentShape(Rectangle())
|
||||
.padding([.leading, .trailing])
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.templateButton(item.description))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ struct SharingStylePickerView: View {
|
||||
.font(.headline)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.exitButton)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -104,6 +105,7 @@ struct SharingStylePickerView: View {
|
||||
.background(Color.green)
|
||||
.cornerRadius(14)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.shareButton)
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, 24)
|
||||
@@ -160,6 +162,7 @@ struct LongestStreakPickerView: View {
|
||||
.font(.headline)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.exitButton)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -169,6 +172,7 @@ struct LongestStreakPickerView: View {
|
||||
selectedMood = mood
|
||||
recomputeStreak()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.moodMenuButton(mood.strValue))
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
@@ -180,6 +184,7 @@ struct LongestStreakPickerView: View {
|
||||
.foregroundColor(textColor.opacity(0.6))
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.moodMenu)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -225,6 +230,7 @@ struct LongestStreakPickerView: View {
|
||||
.background(Color.green)
|
||||
.cornerRadius(14)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.Sharing.shareButton)
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, 24)
|
||||
|
||||
@@ -176,12 +176,13 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.shareButton)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
Color.green
|
||||
)
|
||||
.padding(.trailing, -5)
|
||||
|
||||
|
||||
Button(action: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}, label: {
|
||||
@@ -191,6 +192,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.dismissButton)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
Color.red
|
||||
|
||||
@@ -119,6 +119,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.shareButton)
|
||||
.sheet(isPresented: self.$shareImage.showSheet) {
|
||||
if let uiImage = self.shareImage.selectedShareImage {
|
||||
ShareSheet(photo: uiImage)
|
||||
@@ -129,7 +130,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
Color.green
|
||||
)
|
||||
.padding(.trailing, -5)
|
||||
|
||||
|
||||
Button(action: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}, label: {
|
||||
@@ -139,6 +140,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.dismissButton)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
Color.red
|
||||
|
||||
@@ -167,6 +167,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
selectedMood = mood
|
||||
configureData(fakeData: self.fakeData, mood: self.selectedMood)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.moodMenuButton(mood.strValue))
|
||||
}
|
||||
}, label: {
|
||||
Text("Pick Mood")
|
||||
@@ -174,6 +175,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
.foregroundColor(textColor)
|
||||
.padding()
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.moodMenu)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
theme.currentTheme.secondaryBGColor
|
||||
@@ -194,6 +196,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.shareButton)
|
||||
.sheet(isPresented: self.$shareImage.showSheet) {
|
||||
if let uiImage = self.shareImage.selectedShareImage {
|
||||
ShareSheet(photo: uiImage)
|
||||
@@ -204,7 +207,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
Color.green
|
||||
)
|
||||
.padding(.trailing, -5)
|
||||
|
||||
|
||||
Button(action: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}, label: {
|
||||
@@ -214,6 +217,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.dismissButton)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
Color.red
|
||||
|
||||
@@ -159,6 +159,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.shareButton)
|
||||
.sheet(isPresented: self.$shareImage.showSheet) {
|
||||
if let uiImage = self.shareImage.selectedShareImage {
|
||||
ShareSheet(photo: uiImage)
|
||||
@@ -169,7 +170,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
Color.green
|
||||
)
|
||||
.padding(.trailing, -5)
|
||||
|
||||
|
||||
Button(action: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}, label: {
|
||||
@@ -179,6 +180,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.top, 20)
|
||||
})
|
||||
.accessibilityIdentifier(AccessibilityID.SharingTemplate.dismissButton)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
Color.red
|
||||
|
||||
@@ -93,6 +93,7 @@ struct SwitchableView: View {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityIdentifier(AccessibilityID.SwitchableView.headerToggle)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.padding(.bottom, 30)
|
||||
.onTapGesture {
|
||||
|
||||
@@ -140,6 +140,7 @@ struct TipModalView: View {
|
||||
y: 6
|
||||
)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.TipModal.dismissButton)
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.bottom, 24)
|
||||
.opacity(appeared ? 1 : 0)
|
||||
@@ -308,6 +309,7 @@ struct TipsPreviewView: View {
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.TipModal.tipPreviewButton(index))
|
||||
}
|
||||
} header: {
|
||||
Text("Tap to preview")
|
||||
@@ -320,11 +322,13 @@ struct TipsPreviewView: View {
|
||||
ReflectTipsManager.shared.resetAllTips()
|
||||
}
|
||||
.foregroundColor(.red)
|
||||
.accessibilityIdentifier(AccessibilityID.TipModal.resetTipsButton)
|
||||
|
||||
Toggle("Tips Enabled", isOn: Binding(
|
||||
get: { ReflectTipsManager.shared.tipsEnabled },
|
||||
set: { ReflectTipsManager.shared.tipsEnabled = $0 }
|
||||
))
|
||||
.accessibilityIdentifier(AccessibilityID.TipModal.tipsEnabledToggle)
|
||||
} header: {
|
||||
Text("Settings")
|
||||
}
|
||||
@@ -346,6 +350,7 @@ struct TipsPreviewView: View {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
.accessibilityIdentifier(AccessibilityID.TipModal.doneButton)
|
||||
}
|
||||
}
|
||||
.sheet(item: Binding(
|
||||
|
||||
@@ -308,6 +308,7 @@ struct YearView: View {
|
||||
.preferredColorScheme(theme.preferredColorScheme)
|
||||
#if DEBUG
|
||||
// Triple-tap to toggle demo mode for video recording
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.debugDemoToggle)
|
||||
.onTapGesture(count: 3) {
|
||||
if demoManager.isDemoMode {
|
||||
demoManager.stopDemoMode()
|
||||
|
||||
Reference in New Issue
Block a user