Files
bundesmessenger-ios/bwi/FeatureBanner/MigrationInfoView.swift
2026-03-17 13:55:15 +00:00

414 lines
16 KiB
Swift

//
/*
* Copyright (c) 2025 BWI GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import SwiftUI
// MARK: Migraion Info View
struct MigrationInfoView: View {
@Environment(\.dismiss) var dismissView
@State private var selectedTab = 1
@EnvironmentObject var themeService: BWIThemeService
@State var redrawKey = UUID()
@State var migrationFinished = SharedKeychain.load(account: "migration_finished") == "true"
let username: String
let getUserName: (() -> String?)?
var body: some View {
TabView(selection: $selectedTab) {
if migrationFinished {
MigrationSuccessView()
.tag(1)
} else {
MigrationInfoViewOne()
.tag(1)
if !username.isEmpty || getUserName != nil {
MigrationInfoViewTwo(username: username, getUserName: getUserName)
.tag(2)
}
}
}
.id(redrawKey)
.tabViewStyle(.page)
.tabViewStyle(.page(indexDisplayMode: .always))
.background {
Color(themeService.theme.backgroundColor)
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
}
.onAppear() {
FeatureBannerVisibilityService().markAsRead()
NotificationCenter.default.post(name: .bwiMarkTopBannerAsRead, object: self, userInfo: ["type" : "feature_banner"])
}
.overlay {
VStack() {
HStack() {
Spacer()
Button {
dismissView()
} label: {
Image(Asset.Images.closeButton.name)
.renderingMode(.template)
.resizable()
.frame(width: 36, height: 36)
.foregroundColor(Color(themeService.theme.colors.tertiaryContent))
.padding(20)
}
.accessibilityLabel(BWIL10n.bwiAllCommonClose)
.isHidden(BWIBuildSettings.shared.BuMXMigrationInfoLevel > 2)
}
Spacer()
HStack() {
Button {
withAnimation {
selectedTab = 1
}
} label: {
Image(systemName: "arrow.left")
.resizable()
.frame(width: 24, height: 24)
.foregroundStyle(Color(themeService.theme.colors.tertiaryContent))
.padding(EdgeInsets(top: 20, leading: 30, bottom: 10, trailing: 30))
}
.opacity(selectedTab == 1 ? 0 : 1)
Spacer()
Button {
withAnimation {
selectedTab = 2
}
} label: {
Image(systemName: "arrow.right")
.resizable()
.frame(width: 24, height: 24)
.foregroundStyle(Color(themeService.theme.colors.tertiaryContent))
.padding(EdgeInsets(top: 20, leading: 30, bottom: 10, trailing: 30))
}
.opacity(selectedTab == 2 ? 0 : 1)
}
.isHidden(migrationFinished || BWIBuildSettings.shared.isManagedViaMDM)
if BWIBuildSettings.shared.isManagedViaMDM && BWIBuildSettings.shared.BuMXMigrationInfoLevel < 3 {
Button {
dismissView()
} label: {
Text(BWIL10n.bwiAllCommonGotIt)
.foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
}
.buttonStyle(PrimaryActionButtonStyle())
.padding()
}
}
}
.onAppear {
setupIndicatorColors()
}
.onChange(of: themeService.isCurrentThemeDark) { _ in
setupIndicatorColors()
redrawKey = UUID()
}
.onChange(of: themeService.isCurrentThemeDark) { _ in
setupIndicatorColors()
redrawKey = UUID()
}
}
private func setupIndicatorColors() {
UIPageControl.appearance().currentPageIndicatorTintColor = themeService.theme.textPrimaryColor
UIPageControl.appearance().pageIndicatorTintColor = themeService.theme.textSecondaryColor
}
}
// MARK: Migraion Info View one
struct MigrationInfoViewOne: View {
@EnvironmentObject var themeService: BWIThemeService
var body: some View {
GeometryReader { geo in
ScrollView(.vertical) {
VStack(alignment: .center, spacing: 20) {
Image("migration_detail_1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: geo.size.height * 0.35, alignment: .bottom)
.frame(maxWidth: geo.size.width - 60)
.padding(EdgeInsets(top: 56, leading: 30, bottom: 0, trailing: 30))
.accessibilityHidden(true)
infoText
.frame(width: geo.size.width)
Spacer()
}
.frame(minHeight: geo.size.height)
.frame(width: geo.size.width)
}
.frame(width: geo.size.width, height: geo.size.height)
}
}
var infoText: some View {
VStack(alignment: .leading) {
Text(BWIL10n.bwiMobileDialogMMoreTitle)
.font(.title)
.bold()
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
.padding(.bottom, 20)
if BWIBuildSettings.shared.isManagedViaMDM {
if BWIBuildSettings.shared.BuMXMigrationInfoLevel == 3 {
Text(BWIL10n.bwiMobileDialogM3MoreText1) +
Text(BWIL10n.bwiMobileDialogM1MoreText2).bold() +
Text(BWIL10n.bwiMobileDialogM1MoreText3)
} else {
Text(BWIL10n.bwiMobileDialogM1MoreText3)
}
} else {
if BWIBuildSettings.shared.BuMXMigrationInfoLevel < 3 {
Text(BWIL10n.bwiMobileDialogM1MoreText1) +
Text(BWIL10n.bwiMobileDialogM1MoreText2).bold() +
Text(BWIL10n.bwiMobileDialogM1MoreText3)
} else {
Text(BWIL10n.bwiMobileDialogM3MoreText1) +
Text(BWIL10n.bwiMobileDialogM1MoreText2).bold() +
Text(BWIL10n.bwiMobileDialogM1MoreText3)
}
}
VStack(alignment: .leading) {
HStack(alignment: .top) {
Text("")
Text(BWIL10n.bwiMobileDialogM1MoreTextBullet1)
}
HStack(alignment: .top) {
Text("")
Text(BWIL10n.bwiMobileDialogM1MoreTextBullet2)
}
HStack(alignment: .top) {
Text("")
Text(BWIL10n.bwiMobileDialogM1MoreTextBullet3)
}
HStack(alignment: .top) {
Text("")
Text(BWIL10n.bwiMobileDialogM1MoreTextBullet4)
}
}
.multilineTextAlignment(.leading)
.padding(.leading, 16)
}
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
.padding(EdgeInsets(top: 10, leading: 30, bottom: 0, trailing: 30))
.accessibilityElement(children: .ignore)
.accessibilityLabel(accessibilityLabel)
}
var accessibilityLabel: String {
if BWIBuildSettings.shared.BuMXMigrationInfoLevel < 3 && !BWIBuildSettings.shared.isManagedViaMDM {
return BWIL10n.bwiMobileDialogMMoreTitle + ". " +
BWIL10n.bwiMobileDialogM1MoreText1 +
BWIL10n.bwiMobileDialogM1MoreText2 +
BWIL10n.bwiMobileDialogM1MoreText3 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet1 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet2 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet3 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet4
} else {
return BWIL10n.bwiMobileDialogMMoreTitle + ". " +
BWIL10n.bwiMobileDialogM3MoreText1 +
BWIL10n.bwiMobileDialogM1MoreText2 +
BWIL10n.bwiMobileDialogM1MoreText3 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet1 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet2 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet3 + ", " +
BWIL10n.bwiMobileDialogM1MoreTextBullet4
}
}
}
// MARK: Migraion Info View two
struct MigrationInfoViewTwo: View {
let username: String
let getUserName: (() -> String?)?
@State var lazyLoadedUserName: String? = nil
@State var showSuccessToast: Bool = false
@EnvironmentObject var themeService: BWIThemeService
var body: some View {
GeometryReader { geo in
ScrollView(.vertical) {
VStack(alignment: .center, spacing: 20) {
VStack() {
Image("bumx_logo")
.resizable()
.frame(width: 200, height: 200)
.clipShape(.rect(cornerRadius: 36))
.overlay(
RoundedRectangle(cornerRadius: 36)
.stroke(.gray, lineWidth: 0.4)
)
.accessibilityHidden(true)
}
.frame(height: geo.size.height * 0.35, alignment: .center)
.padding(EdgeInsets(top: 56, leading: 30, bottom: 10, trailing: 30))
instructionsList
successToast
Spacer()
downloadNewAppButton
.frame(maxWidth: 350)
.frame(width: geo.size.width - 100)
.padding(.bottom, 100)
}
.frame(minHeight: geo.size.height)
.frame(width: geo.size.width)
.onAppear {
lazyLoadedUserName = username.isEmpty ? getUserName?() : username
}
}
.frame(width: geo.size.width, height: geo.size.height)
}
}
var instructionsList: some View {
VStack() {
VStack(alignment: .center) {
Text(BWIL10n.bwiMobileDialogMMore2Title)
.font(.title)
.bold()
.padding(.bottom, 20)
}
VStack(alignment: .leading) {
HStack() {
Text("1.")
Button(action: {
UIPasteboard.general.string = lazyLoadedUserName ?? ""
guard !showSuccessToast else { return }
withAnimation {
showSuccessToast = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
withAnimation {
showSuccessToast = false
}
}
}, label: {
Text(BWIL10n.bwiMobileDialogMMore2Text1)
.underline()
.foregroundColor(Color(themeService.theme.textPrimaryColor))
Image(systemName: "square.on.square")
.resizable()
.foregroundColor(Color(themeService.theme.textPrimaryColor))
.frame(width: 15, height: 15)
})
}
HStack() {
Text("2.")
Text(BWIL10n.bwiMobileDialogMMore2Text2)
}
.padding(.bottom, 1)
HStack() {
Text("3.")
Text(BWIL10n.bwiMobileDialogMMore2Text3)
}
}
}
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
.padding(EdgeInsets(top: 10, leading: 30, bottom: 0, trailing: 30))
}
var downloadNewAppButton: some View {
Button(action: {
guard let bumxAppStoreURL = URL(string: "itms-apps://itunes.apple.com/app/id6738500048") else { return }
guard UIApplication.shared.canOpenURL(bumxAppStoreURL) else { return }
UIApplication.shared.open(bumxAppStoreURL, options: [:], completionHandler: nil)
}, label: {
Text(BWIL10n.bwiMobileDialogMMoreButton)
.foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
})
.buttonStyle(PrimaryActionButtonStyle())
}
var successToast: some View {
HStack() {
Image(systemName: "checkmark")
.resizable()
.frame(width: 15, height: 15)
.accessibilityHidden(true)
Text(BWIL10n.bwiMobileDialogMMoreSuccess)
}
.foregroundColor(themeService.isCurrentThemeDark ? .black : .white)
.padding(10)
.background(themeService.isCurrentThemeDark ? .white : .black)
.clipShape(RoundedRectangle(cornerRadius: 10))
.opacity(showSuccessToast ? 1 : 0)
.transition(.opacity)
}
}
// MARK: Migraion Success View
struct MigrationSuccessView: View {
@EnvironmentObject var themeService: BWIThemeService
var body: some View {
GeometryReader { geo in
ScrollView(.vertical) {
VStack(alignment: .center, spacing: 20) {
VStack() {
Image("bumx_logo")
.resizable()
.frame(width: 200, height: 200)
.clipShape(.rect(cornerRadius: 36))
.overlay(
RoundedRectangle(cornerRadius: 36)
.stroke(.gray, lineWidth: 0.4)
)
.accessibilityHidden(true)
}
.frame(height: geo.size.height * 0.35, alignment: .center)
.padding(EdgeInsets(top: 56, leading: 30, bottom: 10, trailing: 30))
VStack {
Text(BWIL10n.bwiMobileDialogM3SuccessChangeTitle)
.font(.title)
.bold()
.padding(.bottom, 20)
Text(BWIL10n.bwiMobileDialogM3SuccessText)
.fixedSize(horizontal: false, vertical: true)
.padding(EdgeInsets(top: 10, leading: 30, bottom: 0, trailing: 30))
}
Spacer()
}
.frame(minHeight: geo.size.height)
.frame(width: geo.size.width)
}
.frame(width: geo.size.width, height: geo.size.height)
}
}
}