feat(globalSSO): Add Ask Admin For Access screen.

Refs: https://gitlab.protontech.ch/apple/shared/protoncore/-/merge_requests/1928
This commit is contained in:
Erik Ackermann 2024-09-27 14:39:50 +00:00
commit 94e7dcf363
9 changed files with 232 additions and 1 deletions

View file

@ -182,6 +182,8 @@ public enum LUITranslation: TranslationsExposing {
case access_granted_description
case access_denied_description
case back_to_signin_button
case request_admin_access_title
case request_admin_access_description
public var l10n: String {
switch self {
@ -496,6 +498,10 @@ public enum LUITranslation: TranslationsExposing {
return localized(key: "Contact your administrator if the problem persists.", comment: "Access Denied screen description")
case .back_to_signin_button:
return localized(key: "Back to sign-in", comment: "Action button title")
case .request_admin_access_title:
return localized(key: "Ask your administrator for access?", comment: "Request Admin for Access screen title")
case .request_admin_access_description:
return localized(key: "This will sign you out of your other devices and you will have to create a new backup password.", comment: "Screen description when prompting the user to request access from their organization admin.")
}
}
}

View file

@ -317,3 +317,7 @@
"Contact your administrator if the problem persists." = "Contact your administrator if the problem persists.";
"Back to sign-in" = "Back to sign-in";
"Ask your administrator for access?" = "Ask your administrator for access?";
"This will sign you out of your other devices and you will have to create a new backup password." = "This will sign you out of your other devices and you will have to create a new backup password.";

View file

@ -0,0 +1,48 @@
//
// RequestAdminAccessViewController.swift
// ProtonCore-LoginUI - Created on 26/09/2024.
//
// Copyright (c) 2024 Proton AG
//
// This file is part of Proton AG and ProtonCore.
//
// ProtonCore is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonCore is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
#if os(iOS)
import Foundation
import ProtonCoreUIFoundations
import SwiftUI
public final class RequestAdminAccessViewController: UIHostingController<RequestAdminAccessView> {
let viewModel: RequestAdminAccessView.ViewModel
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init() {
self.viewModel = RequestAdminAccessView.ViewModel(dependencies: .init())
let view = RequestAdminAccessView(viewModel: self.viewModel)
super.init(rootView: view)
}
override public func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = ColorProvider.BackgroundNorm
}
}
#endif

View file

@ -0,0 +1,57 @@
//
// RequestAdminAccessViewModel.swift
// ProtonCore-LoginUI - Created on 26/09/2024.
//
// Copyright (c) 2024 Proton AG
//
// This file is part of Proton AG and ProtonCore.
//
// ProtonCore is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonCore is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
#if os(iOS)
import SwiftUI
import ProtonCoreUIFoundations
extension RequestAdminAccessView {
struct Dependencies {}
}
extension RequestAdminAccessView {
@MainActor
final class ViewModel: ObservableObject {
init(dependencies: Dependencies) {}
var adminEmailAddress: String {
"admin@privacybydefault.com"
}
var screenTitle: String {
LUITranslation.request_admin_access_title.l10n
}
var bodyDescription: String {
LUITranslation.request_admin_access_description.l10n
}
var continueButtonActionTitle: String {
LUITranslation.continue_core_button.l10n
}
func continueActionButtonTapped() {}
}
}
#endif

View file

@ -0,0 +1,110 @@
//
// SignInRequestView.swift
// ProtonCore-LoginUI - Created on 23/08/2024.
//
// Copyright (c) 2024 Proton AG
//
// This file is part of Proton AG and ProtonCore.
//
// ProtonCore is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonCore is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
#if os(iOS)
import SwiftUI
import ProtonCoreUIFoundations
public struct RequestAdminAccessView: View {
@StateObject var viewModel: ViewModel
private enum Constants {
static let itemSpacing: CGFloat = 24
static let cornerRadius: CGFloat = 8
static let imageSize: CGFloat = 32
static let imagePadding: CGFloat = 8
static let padding: CGFloat = 12
}
public var body: some View {
ScrollView {
VStack(spacing: Constants.itemSpacing) {
Text(viewModel.screenTitle)
.font(.title2)
.fontWeight(.bold)
.frame(maxWidth: .infinity, alignment: .leading)
adminEmailContainer
Text(viewModel.bodyDescription)
.font(.subheadline)
.foregroundColor(ColorProvider.TextWeak)
.frame(maxWidth: .infinity, alignment: .leading)
PCButton(
style: .constant(.init(mode: .solid)),
content: .constant(.init(
title: viewModel.continueButtonActionTitle,
action: viewModel.continueActionButtonTapped
))
)
.padding(.top, Constants.itemSpacing)
Spacer()
}
.padding(Constants.itemSpacing)
.foregroundColor(ColorProvider.TextNorm)
.frame(maxWidth: .infinity)
}
.background(
ColorProvider.BackgroundNorm
.edgesIgnoringSafeArea(.all)
)
}
@ViewBuilder
var adminEmailContainer: some View {
HStack {
organizationImage
Text(viewModel.adminEmailAddress)
.font(.subheadline)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(Constants.padding)
.overlay(
RoundedRectangle(cornerRadius: Constants.cornerRadius)
.stroke(ColorProvider.SeparatorNorm, lineWidth: 1)
)
}
@ViewBuilder
private var organizationImage: some View {
IconProvider.users
.resizable()
.foregroundColor(ColorProvider.White)
.padding(Constants.imagePadding)
.frame(width: Constants.imageSize, height: Constants.imageSize)
.background(ColorProvider.BrandNorm)
.cornerRadius(Constants.cornerRadius)
}
}
#if DEBUG
#Preview {
NavigationView {
RequestAdminAccessView(viewModel: .init(dependencies: .init()))
}
}
#endif
#endif

View file

@ -1,5 +1,5 @@
//
// JoinOrganizationView.swift
// SignInRequestView.swift
// ProtonCore-LoginUI - Created on 23/08/2024.
//
// Copyright (c) 2024 Proton AG

View file

@ -79,6 +79,12 @@ class LoginSSOSnapshotTests: SnapshotTestCase {
checkSnapshots(controller: viewController, perceptualPrecision: defaultPrecision)
}
func testRequestAdminAccess() {
let viewController = RequestAdminAccessViewController()
checkSnapshots(controller: viewController, perceptualPrecision: defaultPrecision)
}
}
#endif