From b29f08cdf679ea99a05600229eb9055a86b31ff9 Mon Sep 17 00:00:00 2001 From: heathermh Date: Wed, 8 Nov 2023 14:11:04 -0800 Subject: [PATCH 1/6] Updated welcome screen to a newer style Updated layout to single screen, updated to be in line with apple standard designs Friendly for dark mode and dynamic text --- FiveCalls/FiveCalls/Localizable.strings | 1 + FiveCalls/FiveCalls/Welcome.swift | 183 +++++++++++++----------- 2 files changed, 100 insertions(+), 84 deletions(-) diff --git a/FiveCalls/FiveCalls/Localizable.strings b/FiveCalls/FiveCalls/Localizable.strings index 061656bc..3be61bd3 100644 --- a/FiveCalls/FiveCalls/Localizable.strings +++ b/FiveCalls/FiveCalls/Localizable.strings @@ -132,6 +132,7 @@ "subheading-message" = "You're making a difference! Calling is the most effective way to influence your representatives, and here's what you've achieved:"; // welcome +"welcome-logo-name" = "Five Calls"; "welcome-page-1-title" = "Make your voice heard"; "welcome-page-1-message" = "Turn your passive participation into active resistance. Facebook likes and Twitter retweets can’t create the change you want to see. Calling your Government on the phone can."; "welcome-page-2-title" = "Spend 5 minutes, make 5 calls."; diff --git a/FiveCalls/FiveCalls/Welcome.swift b/FiveCalls/FiveCalls/Welcome.swift index e2d8f637..e0d3c961 100644 --- a/FiveCalls/FiveCalls/Welcome.swift +++ b/FiveCalls/FiveCalls/Welcome.swift @@ -9,112 +9,127 @@ import SwiftUI struct Welcome: View { + @Environment(\.dismiss) var dismiss @EnvironmentObject var store: Store - - var onContinue: (() -> Void)? - - var body: some View { - VStack { - Image(.fivecallsLogotype) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 292) - .padding(.vertical, 24) - TabView { - Page1() - Page2(onContinue: onContinue) - } - .tabViewStyle(.page) - } - } -} -struct Welcome_Previews: PreviewProvider { - static let previewState = { - var state = AppState() - state.globalCallCount = 12345 - return state - }() + var onContinue: (() -> Void)? - static let previewStore = Store(state: previewState, middlewares: [appMiddleware()]) - - static var previews: some View { - Welcome().environmentObject(previewStore) - } -} + struct CustomLabel: LabelStyle { + var spacing: Double = 0.0 -struct Page1: View { - var body: some View { - VStack(alignment: .leading, spacing: 20) { - Text(R.string.localizable.welcomePage1Title()) - .font(.title) - .textCase(.uppercase) - .foregroundStyle(.fivecallsDarkBlueText) - Text(R.string.localizable.welcomePage1Message()) - .font(.headline) - .foregroundStyle(.fivecallsDarkBlueText) - Spacer() + func makeBody(configuration: Configuration) -> some View { + HStack(spacing: spacing) { + configuration.icon + configuration.title + } } - .padding(EdgeInsets(top: 24, leading: 24, bottom: 20, trailing: 24)) } -} -struct Page2: View { - @Environment(\.dismiss) var dismiss - @EnvironmentObject var store: Store - - var onContinue: (() -> Void)? - var subMessage: String { guard store.state.globalCallCount > 0 else { return "" } - + return String(format: R.string.localizable.welcomePage2Calls( StatsViewModel(numberOfCalls: store.state.globalCallCount).formattedNumberOfCalls) ) } - + var subMessageOpacity: Double { store.state.globalCallCount > 0 ? 1 : 0 } var body: some View { - VStack(alignment: .leading, spacing: 10) { - Text(R.string.localizable.welcomePage2Title()) - .font(.title) - .foregroundStyle(.fivecallsDarkBlueText) - Text(R.string.localizable.welcomePage2Message()) - .font(.headline) - .foregroundStyle(.fivecallsDarkBlueText) - Text(subMessage) - .font(.headline) - .textCase(.uppercase) - .foregroundStyle(.fivecallsDarkBlueText) - .opacity(subMessageOpacity) - .animation(.easeIn, value: subMessageOpacity) - Spacer() - Button(action: { - onContinue?() - dismiss() - }) { - Text(R.string.localizable.welcomePage2ButtonTitle()) - .fontWeight(.semibold) - .foregroundColor(.white) - .font(.system(size: 30)) - } - .padding() - .frame(maxWidth: .infinity, minHeight: 73) - .background { - RoundedRectangle(cornerRadius: 6) - .foregroundColor(Color.fivecallsDarkBlue) + ScrollView { + VStack { + Image(decorative: R.image.fivecallsLogotype) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 292) + .padding(.vertical, 24) + + VStack(alignment: .leading, spacing: 30) { + Label { + VStack(alignment: .leading) { + Text(R.string.localizable.welcomePage1Title()) + .fontWeight(.heavy) + .multilineTextAlignment(.leading) + Text(R.string.localizable.welcomePage1Message()) + .multilineTextAlignment(.leading) + } + .accessibilityElement(children: .combine) + } icon: { + Image(systemName: "phone.badge.waveform") + .symbolRenderingMode(.palette) + .foregroundStyle(.fivecallsRed, .fivecallsDarkBlue) + } + .labelStyle(CustomLabel(spacing: 20)) + + Label { + VStack(alignment: .leading) { + Text(R.string.localizable.welcomePage2Title()) + .fontWeight(.heavy) + Text(R.string.localizable.welcomePage2Message()) + } + .accessibilityElement(children: .combine) + } icon: { + Image(systemName: "goforward.5") + .foregroundStyle(.fivecallsDarkBlue) + } + .labelStyle(CustomLabel(spacing: 20)) + + Label { + VStack(alignment: .leading) { + Text(subMessage) + .fontWeight(.heavy) + .opacity(subMessageOpacity) + } + .accessibilityElement(children: .combine) + } icon: { + Image(systemName: "person.2") + .opacity(subMessageOpacity) + .symbolRenderingMode(.palette) + .foregroundStyle(.fivecallsGreen, .fivecallsDarkBlue) + } + .labelStyle(CustomLabel(spacing: 12)) + Spacer() + Button(action: { + onContinue?() + dismiss() + }) { + // TODO: update string if needed + // Text(R.string.localizable.welcomePage2ButtonTitle()) + Text("Continue") + .foregroundColor(.white) + } + .padding() + .frame(maxWidth: .infinity) + .background { + RoundedRectangle(cornerRadius: 6) + .foregroundColor(.fivecallsDarkBlue) + } + } + .padding(30) } - } - .padding(EdgeInsets(top: 24, leading: 24, bottom: 48, trailing: 24)) - .onAppear() { - if store.state.globalCallCount == 0 { - store.dispatch(action: .FetchStats(nil)) + .onAppear() { + if store.state.globalCallCount == 0 { + store.dispatch(action: .FetchStats(nil)) + } } } } } + +struct Welcome_Previews: PreviewProvider { + static let previewState = { + var state = AppState() + state.globalCallCount = 12345 + return state + }() + + static let previewStore = Store(state: previewState, middlewares: [appMiddleware()]) + + static var previews: some View { + Welcome().environmentObject(previewStore) + } +} From b9c36870e6b9f0bc409521731a54f4d4bb5d8f44 Mon Sep 17 00:00:00 2001 From: heathermh Date: Fri, 10 Nov 2023 15:21:55 -0800 Subject: [PATCH 2/6] Updates to layout for welcome view Switched to grid Adjusted size/color of symbols --- FiveCalls/FiveCalls/Localizable.strings | 13 ++- FiveCalls/FiveCalls/Welcome.swift | 126 ++++++++++-------------- 2 files changed, 59 insertions(+), 80 deletions(-) diff --git a/FiveCalls/FiveCalls/Localizable.strings b/FiveCalls/FiveCalls/Localizable.strings index 3be61bd3..1fd6a760 100644 --- a/FiveCalls/FiveCalls/Localizable.strings +++ b/FiveCalls/FiveCalls/Localizable.strings @@ -132,13 +132,12 @@ "subheading-message" = "You're making a difference! Calling is the most effective way to influence your representatives, and here's what you've achieved:"; // welcome -"welcome-logo-name" = "Five Calls"; -"welcome-page-1-title" = "Make your voice heard"; -"welcome-page-1-message" = "Turn your passive participation into active resistance. Facebook likes and Twitter retweets can’t create the change you want to see. Calling your Government on the phone can."; -"welcome-page-2-title" = "Spend 5 minutes, make 5 calls."; -"welcome-page-2-message" = "Calling is the most effective way to influence your representative."; -"welcome-page-2-calls" = "Together we've made\n%@ calls"; -"welcome-page-2-button-title" = "Get Started"; +"welcome-section-1-title" = "Make your voice heard"; +"welcome-section-1-message" = "Turn your passive participation into active resistance. Facebook likes and Twitter retweets can’t create the change you want to see. Calling your Government on the phone can."; +"welcome-section-2-title" = "Spend 5 minutes, make 5 calls"; +"welcome-section-2-message" = "Calling is the most effective way to influence your representative."; +"welcome-section-3-calls" = "Together we've made\n%@ calls"; +"welcome-button-title" = "Continue"; // done "done-title" = "You called on **%@**"; diff --git a/FiveCalls/FiveCalls/Welcome.swift b/FiveCalls/FiveCalls/Welcome.swift index e0d3c961..45a3cf4a 100644 --- a/FiveCalls/FiveCalls/Welcome.swift +++ b/FiveCalls/FiveCalls/Welcome.swift @@ -14,23 +14,12 @@ struct Welcome: View { var onContinue: (() -> Void)? - struct CustomLabel: LabelStyle { - var spacing: Double = 0.0 - - func makeBody(configuration: Configuration) -> some View { - HStack(spacing: spacing) { - configuration.icon - configuration.title - } - } - } - var subMessage: String { guard store.state.globalCallCount > 0 else { return "" } - return String(format: R.string.localizable.welcomePage2Calls( + return String(format: R.string.localizable.welcomeSection3Calls( StatsViewModel(numberOfCalls: store.state.globalCallCount).formattedNumberOfCalls) ) } @@ -41,81 +30,72 @@ struct Welcome: View { var body: some View { ScrollView { - VStack { + Grid(verticalSpacing: 30) { Image(decorative: R.image.fivecallsLogotype) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 292) .padding(.vertical, 24) - - VStack(alignment: .leading, spacing: 30) { - Label { - VStack(alignment: .leading) { - Text(R.string.localizable.welcomePage1Title()) - .fontWeight(.heavy) - .multilineTextAlignment(.leading) - Text(R.string.localizable.welcomePage1Message()) - .multilineTextAlignment(.leading) - } - .accessibilityElement(children: .combine) - } icon: { - Image(systemName: "phone.badge.waveform") - .symbolRenderingMode(.palette) - .foregroundStyle(.fivecallsRed, .fivecallsDarkBlue) - } - .labelStyle(CustomLabel(spacing: 20)) - - Label { - VStack(alignment: .leading) { - Text(R.string.localizable.welcomePage2Title()) - .fontWeight(.heavy) - Text(R.string.localizable.welcomePage2Message()) - } - .accessibilityElement(children: .combine) - } icon: { - Image(systemName: "goforward.5") - .foregroundStyle(.fivecallsDarkBlue) + GridRow() { + Image(systemName: "phone.badge.waveform") + .symbolRenderingMode(.palette) + .foregroundStyle(.red, .blue) + .font(.title) + .accessibilityHidden(true) + VStack(alignment: .leading) { + Text(R.string.localizable.welcomeSection1Title()) + .fontWeight(.heavy) + Text(R.string.localizable.welcomeSection1Message()) } - .labelStyle(CustomLabel(spacing: 20)) - - Label { - VStack(alignment: .leading) { - Text(subMessage) - .fontWeight(.heavy) - .opacity(subMessageOpacity) - } - .accessibilityElement(children: .combine) - } icon: { - Image(systemName: "person.2") - .opacity(subMessageOpacity) - .symbolRenderingMode(.palette) - .foregroundStyle(.fivecallsGreen, .fivecallsDarkBlue) - } - .labelStyle(CustomLabel(spacing: 12)) - Spacer() - Button(action: { - onContinue?() - dismiss() - }) { - // TODO: update string if needed - // Text(R.string.localizable.welcomePage2ButtonTitle()) - Text("Continue") - .foregroundColor(.white) - } - .padding() - .frame(maxWidth: .infinity) - .background { - RoundedRectangle(cornerRadius: 6) - .foregroundColor(.fivecallsDarkBlue) + .accessibilityElement(children: .combine) + } + GridRow() { + Image(systemName: "goforward.5") + .foregroundStyle(.blue) + .font(.title) + .accessibilityHidden(true) + VStack(alignment: .leading) { + Text(R.string.localizable.welcomeSection2Title()) + .fontWeight(.heavy) + Text(R.string.localizable.welcomeSection2Message()) } + .accessibilityElement(children: .combine) + } + GridRow() { + Image(systemName: "person.2") + .opacity(subMessageOpacity) + .symbolRenderingMode(.palette) + .foregroundStyle(.blue, .red) + .font(.title) + .accessibilityHidden(true) + Text(subMessage) + .fontWeight(.heavy) + .opacity(subMessageOpacity) + .gridColumnAlignment(.leading) + } + Spacer() + Spacer() + Button(action: { + onContinue?() + dismiss() + }) { + Text(R.string.localizable.welcomeButtonTitle()) + .foregroundColor(.white) + } + .padding() + .frame(maxWidth: .infinity) + .background { + RoundedRectangle(cornerRadius: 6) + .foregroundColor(.blue) } - .padding(30) } .onAppear() { if store.state.globalCallCount == 0 { store.dispatch(action: .FetchStats(nil)) } } + .frame(maxWidth: .infinity) + .padding(30) } } } From cff53d9dfce586fa293a51abc7c7c36844da432a Mon Sep 17 00:00:00 2001 From: heathermh Date: Fri, 10 Nov 2023 16:20:49 -0800 Subject: [PATCH 3/6] Accessibility improvements to dashboard and location picker Grouped items, updated accessibility labels to make it easier to navigate top portion of dashboard and select a location using VoiceOver. --- FiveCalls/FiveCalls/Dashboard.swift | 5 ++++- FiveCalls/FiveCalls/Localizable.strings | 1 + FiveCalls/FiveCalls/LocationHeader.swift | 6 ++++++ FiveCalls/FiveCalls/LocationSheet.swift | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/FiveCalls/FiveCalls/Dashboard.swift b/FiveCalls/FiveCalls/Dashboard.swift index b10213b7..d8846cb1 100644 --- a/FiveCalls/FiveCalls/Dashboard.swift +++ b/FiveCalls/FiveCalls/Dashboard.swift @@ -34,6 +34,7 @@ struct Dashboard: View { } Image(.fivecallsStars) + .accessibilityHidden(true) } .padding(.horizontal, 10) .padding(.bottom, 10) @@ -42,7 +43,8 @@ struct Dashboard: View { .font(.system(size: 20)) .fontWeight(.semibold) .padding(.horizontal, 10) - + .accessibilityAddTraits(.isHeader) + IssuesList(store: store, selectedIssue: $selectedIssue, showAllIssues: $showAllIssues) } .navigationBarHidden(true) @@ -99,6 +101,7 @@ struct MenuView: View { } } label: { Image(.gear).renderingMode(.template).tint(Color.fivecallsDarkBlue) + .accessibilityLabel(Text(R.string.localizable.menuName)) } .popoverTipIfApplicable( title: Text(R.string.localizable.menuTipTitle()), diff --git a/FiveCalls/FiveCalls/Localizable.strings b/FiveCalls/FiveCalls/Localizable.strings index 1fd6a760..f02781b6 100644 --- a/FiveCalls/FiveCalls/Localizable.strings +++ b/FiveCalls/FiveCalls/Localizable.strings @@ -38,6 +38,7 @@ "choose-issue-subheading" = "More details about this issue will appear here"; // dashboard +"menu-name" = "Menu"; "menu-scheduled-reminders" = "Reminders"; "menu-your-impact" = "Your Impact"; "menu-about" = "About"; diff --git a/FiveCalls/FiveCalls/LocationHeader.swift b/FiveCalls/FiveCalls/LocationHeader.swift index 21f77a05..3a18883e 100644 --- a/FiveCalls/FiveCalls/LocationHeader.swift +++ b/FiveCalls/FiveCalls/LocationHeader.swift @@ -53,6 +53,9 @@ struct LocationHeader: View { .padding(.trailing) .padding(.leading, 7) } + .accessibilityElement(children: .ignore) + .accessibilityLabel(Text("Your location is: \(location!.locationDisplay)")) + .accessibilityAddTraits(.isButton) } var unsetLocationView: some View { @@ -71,6 +74,9 @@ struct LocationHeader: View { .padding(.trailing) .padding(.leading, 7) } + .accessibilityElement(children: .ignore) + .accessibilityLabel(Text("Set your location")) + .accessibilityAddTraits(.isButton) } } diff --git a/FiveCalls/FiveCalls/LocationSheet.swift b/FiveCalls/FiveCalls/LocationSheet.swift index aed3ba9a..18c85971 100644 --- a/FiveCalls/FiveCalls/LocationSheet.swift +++ b/FiveCalls/FiveCalls/LocationSheet.swift @@ -54,11 +54,13 @@ struct LocationSheet: View { .onTapGesture { locationSearch() } + .accessibilityHidden(true) } Text("Use an address, zip code or zip + 4") .font(.footnote) .foregroundColor(.secondary) .padding(.leading, 35) + .accessibilityHidden(true) } .padding(.bottom) HStack(alignment: .top) { @@ -99,6 +101,8 @@ struct LocationSheet: View { } } } + .accessibilityElement(children: .ignore) + .accessibilityLabel(Text("Detect my location")) } } From ae397720b79c706ef2383ede43d267843209f990 Mon Sep 17 00:00:00 2001 From: heathermh Date: Fri, 10 Nov 2023 17:03:45 -0800 Subject: [PATCH 4/6] Added button to detect my location --- FiveCalls/FiveCalls/LocationSheet.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/FiveCalls/FiveCalls/LocationSheet.swift b/FiveCalls/FiveCalls/LocationSheet.swift index 18c85971..236c6bb2 100644 --- a/FiveCalls/FiveCalls/LocationSheet.swift +++ b/FiveCalls/FiveCalls/LocationSheet.swift @@ -103,6 +103,7 @@ struct LocationSheet: View { } .accessibilityElement(children: .ignore) .accessibilityLabel(Text("Detect my location")) + .accessibilityAddTraits(.isButton) } } From 9611ccec06bfe1e50eba9acb03ba9dafa5715210 Mon Sep 17 00:00:00 2001 From: heathermh Date: Sat, 11 Nov 2023 12:33:18 -0800 Subject: [PATCH 5/6] Added location / set location string to localizable --- FiveCalls/FiveCalls/Localizable.strings | 4 ++++ FiveCalls/FiveCalls/LocationHeader.swift | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/FiveCalls/FiveCalls/Localizable.strings b/FiveCalls/FiveCalls/Localizable.strings index f02781b6..02679b51 100644 --- a/FiveCalls/FiveCalls/Localizable.strings +++ b/FiveCalls/FiveCalls/Localizable.strings @@ -70,6 +70,10 @@ "next-contact" = "Next contact"; "done-calling" = "Done calling"; +// location +"your-location-is" = "Your location is:"; +"set-your-location" = "Set your location"; + // location detection "locating-temp" = "Locating..."; "unknown-location" = "Unknown Location"; diff --git a/FiveCalls/FiveCalls/LocationHeader.swift b/FiveCalls/FiveCalls/LocationHeader.swift index 3a18883e..e01967e5 100644 --- a/FiveCalls/FiveCalls/LocationHeader.swift +++ b/FiveCalls/FiveCalls/LocationHeader.swift @@ -38,7 +38,7 @@ struct LocationHeader: View { var locationView: some View { HStack { VStack(alignment: .leading) { - Text("Your location is:") + Text(R.string.localizable.yourLocationIs) .font(.footnote) Text(location!.locationDisplay) .font(.system(.title3)) @@ -54,14 +54,14 @@ struct LocationHeader: View { .padding(.leading, 7) } .accessibilityElement(children: .ignore) - .accessibilityLabel(Text("Your location is: \(location!.locationDisplay)")) + .accessibilityLabel(Text("\(R.string.localizable.yourLocationIs()) \(location!.locationDisplay)")) .accessibilityAddTraits(.isButton) } var unsetLocationView: some View { HStack { VStack(alignment: .leading) { - Text("Set your location") + Text(R.string.localizable.setYourLocation) .font(.system(.title3)) .fontWeight(.medium) } @@ -75,7 +75,7 @@ struct LocationHeader: View { .padding(.leading, 7) } .accessibilityElement(children: .ignore) - .accessibilityLabel(Text("Set your location")) + .accessibilityLabel(Text(R.string.localizable.setYourLocation)) .accessibilityAddTraits(.isButton) } } From 14506e90f08ef00969b3e4660004ab07ee1b8e98 Mon Sep 17 00:00:00 2001 From: heathermh Date: Sat, 11 Nov 2023 12:38:23 -0800 Subject: [PATCH 6/6] Switched welcome screen button back to "Get Started" --- FiveCalls/FiveCalls/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FiveCalls/FiveCalls/Localizable.strings b/FiveCalls/FiveCalls/Localizable.strings index 02679b51..57d4e58b 100644 --- a/FiveCalls/FiveCalls/Localizable.strings +++ b/FiveCalls/FiveCalls/Localizable.strings @@ -142,7 +142,7 @@ "welcome-section-2-title" = "Spend 5 minutes, make 5 calls"; "welcome-section-2-message" = "Calling is the most effective way to influence your representative."; "welcome-section-3-calls" = "Together we've made\n%@ calls"; -"welcome-button-title" = "Continue"; +"welcome-button-title" = "Get Started"; // done "done-title" = "You called on **%@**";