Skip to content

Commit

Permalink
Tmp UI and flow
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-magda committed Sep 21, 2023
1 parent 15042e7 commit d23acbd
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 26 deletions.
14 changes: 13 additions & 1 deletion iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
2C66720F2A529A7C0040EA2F /* ProgressScreenTrackProgressSkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C66720E2A529A7C0040EA2F /* ProgressScreenTrackProgressSkeletonView.swift */; };
2C688C032A4E8F900061AFFD /* ProgressScreenTrackProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C688C022A4E8F900061AFFD /* ProgressScreenTrackProgressView.swift */; };
2C688C052A4E97750061AFFD /* ProgressScreenProjectProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C688C042A4E97750061AFFD /* ProgressScreenProjectProgressView.swift */; };
2C68FD7C2ABC1FF700D9EBE2 /* NotificationsOnboardingContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C68FD7B2ABC1FF700D9EBE2 /* NotificationsOnboardingContentView.swift */; };
2C7036E82943A2A800775E87 /* ProblemOfDaySkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C7036E72943A2A800775E87 /* ProblemOfDaySkeletonView.swift */; };
2C7036EA2943A34000775E87 /* TopicsRepetitionsCardSkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C7036E92943A34000775E87 /* TopicsRepetitionsCardSkeletonView.swift */; };
2C708D3228E5AA700061A8DB /* KotlinThrowable+AsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C708D3128E5AA700061A8DB /* KotlinThrowable+AsError.swift */; };
Expand Down Expand Up @@ -782,6 +783,7 @@
2C66720E2A529A7C0040EA2F /* ProgressScreenTrackProgressSkeletonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressScreenTrackProgressSkeletonView.swift; sourceTree = "<group>"; };
2C688C022A4E8F900061AFFD /* ProgressScreenTrackProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressScreenTrackProgressView.swift; sourceTree = "<group>"; };
2C688C042A4E97750061AFFD /* ProgressScreenProjectProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressScreenProjectProgressView.swift; sourceTree = "<group>"; };
2C68FD7B2ABC1FF700D9EBE2 /* NotificationsOnboardingContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsOnboardingContentView.swift; sourceTree = "<group>"; };
2C7036E72943A2A800775E87 /* ProblemOfDaySkeletonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemOfDaySkeletonView.swift; sourceTree = "<group>"; };
2C7036E92943A34000775E87 /* TopicsRepetitionsCardSkeletonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopicsRepetitionsCardSkeletonView.swift; sourceTree = "<group>"; };
2C708D3128E5AA700061A8DB /* KotlinThrowable+AsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KotlinThrowable+AsError.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2066,6 +2068,15 @@
path = Skeleton;
sourceTree = "<group>";
};
2C68FD7D2ABC351D00D9EBE2 /* Views */ = {
isa = PBXGroup;
children = (
2C68FD7B2ABC1FF700D9EBE2 /* NotificationsOnboardingContentView.swift */,
3944E4546DEF47A28B2E7292 /* NotificationsOnboardingView.swift */,
);
path = Views;
sourceTree = "<group>";
};
2C725B5C28090CE500A49043 /* SwiftUI */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3131,8 +3142,8 @@
isa = PBXGroup;
children = (
C2D19C8A442CF9C4F00370B8 /* NotificationsOnboardingAssembly.swift */,
3944E4546DEF47A28B2E7292 /* NotificationsOnboardingView.swift */,
E3570563AEEEEF2F5495BCA6 /* NotificationsOnboardingViewModel.swift */,
2C68FD7D2ABC351D00D9EBE2 /* Views */,
);
path = NotificationsOnboarding;
sourceTree = "<group>";
Expand Down Expand Up @@ -3951,6 +3962,7 @@
2C963BC52812D1A70036DD53 /* HomeView.swift in Sources */,
2C93C2D8292EBBB5004D1861 /* AuthSocialFeatureStateKsExtensions.swift in Sources */,
E9101713283296F3002E70F5 /* RadioButton.swift in Sources */,
2C68FD7C2ABC1FF700D9EBE2 /* NotificationsOnboardingContentView.swift in Sources */,
2C20FBC2284F66FC006D879E /* NSAttributedString+TrimmingCharacters.swift in Sources */,
2C20B28A286C350C000F458A /* CodeEditor.swift in Sources */,
2C919DE827EEEDD60022A2F2 /* LinkedList.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"images" : [
{
"filename" : "notifications-onboarding-illustration-light.pdf",
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "notifications-onboarding-illustration-dark.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ enum Images {
static let problemOfDayCard = "onboarding-problem-of-day-card"
}

// MARK: - NotificationsOnboarding -

enum NotificationsOnboarding {
static let illustration = "notifications-onboarding-illustration"
}

// MARK: - TopicsRepetitions -

enum TopicsRepetitions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,18 @@ enum Strings {
static let signUp = sharedStrings.onboarding_sign_up.localized()
}

// MARK: - NotificationsOnboarding -

enum NotificationsOnboarding {
static let title = "Track your progress"
static let subtitle = """
Enable notifications to keep your streak alive and stay consistently on top of your learning
"""

static let buttonPrimary = "Allow notifications"
static let buttonSecondary = "Remind me later"
}

// MARK: - ProjectSelectionList -

enum ProjectSelectionList {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,18 @@ final class AppViewModel: FeatureViewModel<AppFeatureState, AppFeatureMessage, A

extension AppViewModel: AuthOutputProtocol {
func handleUserAuthorized(profile: Profile) {
#warning("ALTAPPS-971: Provide isNotificationPermissionGranted")
onNewMessage(
AppFeatureMessageUserAuthorized(
profile: profile,
isNotificationPermissionGranted: false
)
)
Task(priority: .userInitiated) {
let currentAuthorizationStatus = await NotificationPermissionStatus.current

await MainActor.run {
onNewMessage(
AppFeatureMessageUserAuthorized(
profile: profile,
isNotificationPermissionGranted: currentAuthorizationStatus.isRegistered
)
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ extension AppViewController: AppViewControllerProtocol {
navigationController.navigationBar.prefersLargeTitles = true
return navigationController
case .notificationOnBoardingScreen:
#warning("ALTAPPS-971: Route to the NotificationOnBoardingScreen")
fatalError("NotificationOnBoardingScreen is not implemented yet!")
let assembly = NotificationsOnboardingAssembly()
return assembly.makeModule()
}
}()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ final class NotificationsOnboardingAssembly: UIKitAssembly {
let notificationsOnboardingComponent = AppGraphBridge.sharedAppGraph.buildNotificationsOnboardingComponent()

let notificationsOnboardingViewModel = NotificationsOnboardingViewModel(
feature: notificationsOnboardingComponent.notificationOnboardingFeature
notificationsRegistrationService: .shared,
feature: notificationsOnboardingComponent.notificationsOnboardingFeature
)

let notificationsOnboardingView = NotificationsOnboardingView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,45 @@ final class NotificationsOnboardingViewModel: FeatureViewModel<
NotificationsOnboardingFeatureMessage,
NotificationsOnboardingFeatureActionViewAction
> {
private let notificationsRegistrationService: NotificationsRegistrationService

init(
notificationsRegistrationService: NotificationsRegistrationService,
feature: Presentation_reduxFeature
) {
self.notificationsRegistrationService = notificationsRegistrationService
super.init(feature: feature)
}

override func shouldNotifyStateDidChange(
oldState: NotificationsOnboardingFeature.State,
newState: NotificationsOnboardingFeature.State
) -> Bool {
false
}

func doPrimaryAction() {
onNewMessage(NotificationsOnboardingFeatureMessageAllowNotificationClicked())
}

func doSecondaryAction() {
onNewMessage(NotificationsOnboardingFeatureMessageRemindMeLaterClicked())
}

func doRequestNotificationPermission() {
Task(priority: .userInitiated) {
let isGranted = await notificationsRegistrationService.requestAuthorizationIfNeeded()

await MainActor.run {
onNewMessage(
NotificationsOnboardingFeatureMessageNotificationPermissionRequestResult(
isPermissionGranted: isGranted
)
)
}
}
}

// MARK: Analytic

func logViewedEvent() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import SwiftUI

extension NotificationsOnboardingContentView {
struct Appearance {
let interitemSpacing = LayoutInsets.smallInset

let illustrationHeight: CGFloat = 320

let maxWidth: CGFloat = DeviceInfo.current.isPad ? 400 : .infinity

let primaryButtonStyle = RoundedRectangleButtonStyle(style: .violet)
}
}

struct NotificationsOnboardingContentView: View {
private(set) var appearance = Appearance()

@Environment(\.horizontalSizeClass) private var horizontalSizeClass

private let actionButtonsFeedbackGenerator = FeedbackGenerator(feedbackType: .selection)

let onPrimaryButtonTap: () -> Void
let onSecondaryButtonTap: () -> Void

var body: some View {
VerticalCenteredScrollView(showsIndicators: false) {
VStack(spacing: 0) {
if horizontalSizeClass == .regular {
Spacer()
}

VStack(spacing: 0) {
if horizontalSizeClass == .compact {
Spacer()
}
header
.padding(.vertical)
if horizontalSizeClass == .compact {
Spacer()
}

illustration
.padding(.vertical)
if horizontalSizeClass == .compact {
Spacer()
}

actionButtons
.padding(.top)
}

if horizontalSizeClass == .regular {
Spacer()
}
}
.padding()
.frame(maxWidth: appearance.maxWidth)
}
}

private var header: some View {
VStack(alignment: .center, spacing: appearance.interitemSpacing) {
Text(Strings.NotificationsOnboarding.title)
.font(.title).bold()
.foregroundColor(.primaryText)

Text(Strings.NotificationsOnboarding.subtitle)
.font(.body)
.foregroundColor(.secondaryText)
}
.multilineTextAlignment(.center)
}

private var illustration: some View {
Image(Images.NotificationsOnboarding.illustration)
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity)
.frame(maxHeight: appearance.illustrationHeight)
}

@MainActor
private var actionButtons: some View {
VStack(alignment: .center, spacing: appearance.interitemSpacing) {
Button(
Strings.NotificationsOnboarding.buttonPrimary,
action: {
actionButtonsFeedbackGenerator.triggerFeedback()
onPrimaryButtonTap()
}
)
.buttonStyle(appearance.primaryButtonStyle)
.shineEffect()

Button(
Strings.NotificationsOnboarding.buttonSecondary,
action: {
actionButtonsFeedbackGenerator.triggerFeedback()
onSecondaryButtonTap()
}
)
.frame(
maxWidth: .infinity,
minHeight: appearance.primaryButtonStyle.minHeight,
alignment: .center
)
}
}
}

struct NotificationsOnboardingContentView_Previews: PreviewProvider {
static var previews: some View {
NotificationsOnboardingContentView(
onPrimaryButtonTap: {},
onSecondaryButtonTap: {}
)
.previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro"))

NotificationsOnboardingContentView(
onPrimaryButtonTap: {},
onSecondaryButtonTap: {}
)
.previewDevice(PreviewDevice(rawValue: "iPad (10th generation)"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ struct NotificationsOnboardingView: View {

BackgroundView(color: appearance.backgroundColor)

buildBody()
NotificationsOnboardingContentView(
onPrimaryButtonTap: viewModel.doPrimaryAction,
onSecondaryButtonTap: viewModel.doSecondaryAction
)
}
.onAppear {
viewModel.startListening()
Expand All @@ -29,13 +32,6 @@ struct NotificationsOnboardingView: View {
viewModel.onViewAction = nil
}
}

// MARK: Private API

@ViewBuilder
private func buildBody() -> some View {
Text("Hello, World!")
}
}

// MARK: - NotificationsOnboardingView (ViewAction) -
Expand All @@ -48,7 +44,7 @@ private extension NotificationsOnboardingView {
case .completeNotificationOnboarding:
#warning("TODO")
case .requestNotificationPermission:
#warning("TODO")
viewModel.doRequestNotificationPermission()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ final class ProfileAssembly: Assembly {
presentationDescription: presentationDescription,
profileViewDataMapper: ProfileViewDataMapper(),
badgesViewStateMapper: profileComponent.badgesViewStateMapper,
notificationService: NotificationsService(
notificationInteractor: notificationComponent.notificationInteractor
),
notificationsRegistrationService: .shared,
notificationInteractor: notificationComponent.notificationInteractor,
feature: profileComponent.profileFeature
Expand Down
Loading

0 comments on commit d23acbd

Please sign in to comment.