diff --git a/Config/BWIBuildSettings.swift b/Config/BWIBuildSettings.swift index 3b07bf08e..4ad67dacb 100644 --- a/Config/BWIBuildSettings.swift +++ b/Config/BWIBuildSettings.swift @@ -677,7 +677,7 @@ class BWIBuildSettings: NSObject { var isLabsFederationEnabled // Migration status from wellknown config - @UserDefault(key: UserDefaultsKeys.BuMXMigrationInfoLevelKey, defaultValue: 0, storage: RiotSettings.defaults) + @UserDefault(key: UserDefaultsKeys.BuMXMigrationInfoLevelKey, defaultValue: 1, storage: RiotSettings.defaults) var BuMXMigrationInfoLevel // Migration level already shown diff --git a/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/BuM_Appicon-next_iOS_1024.png b/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/BuM_Appicon-next_iOS_1024.png new file mode 100644 index 000000000..7b4cd0a18 Binary files /dev/null and b/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/BuM_Appicon-next_iOS_1024.png differ diff --git a/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/Contents.json b/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/Contents.json new file mode 100644 index 000000000..905cce3a2 --- /dev/null +++ b/Riot/Assets/SharedImages.xcassets/bumx_logo.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "BuM_Appicon-next_iOS_1024.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/de.lproj/Bwi.strings b/Riot/Assets/de.lproj/Bwi.strings index 695ad1f84..55977f55e 100644 --- a/Riot/Assets/de.lproj/Bwi.strings +++ b/Riot/Assets/de.lproj/Bwi.strings @@ -748,8 +748,28 @@ "room_error_join_failed_federation_disabled_message" = "Du kannst den Raum nicht beitreten. Grund: Die Föderation wurde für diesen Raum aufgehoben."; // MARK: migration to new client +// Banner "bwi_mobile_dialog_m_banner_title" = "Wechsel zum BundesMessengerX"; "bwi_mobileMdialog_m1_banner_text" = "Das ist eine neue, technisch optimierte App vom BuM. Du kannst sie jetzt schon ausprobieren, bevor bald alle umsteigen müssen."; "bwi_mobileMdialog_m1_banner_text_bold" = " Alle deine Kontakte und Nachrichten bleiben erhalten."; "bwi_mobile_dialog_m_banner_button2" = "Erfahre mehr"; "bwi_mobile_dialog_m_banner_button1" = "Später erinnern"; + +// Sheet page 1 +"bwi_mobile_dialog_m_more_title" = "BundesMessengerX"; + +"bwi_mobile_dialog_m1_more_text_1" = "Diese App wird bald abgeschaltet und durch eine neue technisch optimierte App ersetzt "; +"bwi_mobile_dialog_m1_more_text_2" = "(alle deine Kontakte und Nachrichten bleiben erhalten)."; +"bwi_mobile_dialog_m1_more_text_3" = "\n\nDich erwartet u.a.:"; +"bwi_mobile_dialog_m1_more_text_bullet_1" = "schnellere Performance"; +"bwi_mobile_dialog_m1_more_text_bullet_2" = "verbessertes Design"; +"bwi_mobile_dialog_m1_more_text_bullet_3" = "neue Funktionen, wie Nachrichten anheften"; +"bwi_mobile_dialog_m1_more_text_bullet_4" = "optimierte Barrierefreiheit"; + +// Sheet page 2 +"bwi_mobile_dialog_m_more2_title" = "Wechsel jetzt:"; +"bwi_mobile_dialog_m_more2_text_1" = "Benutzername hier kopieren"; +"bwi_mobile_dialog_m_more2_text_2" = "App über den Button herunterladen"; +"bwi_mobile_dialog_m_more2_text_3" = "Mit deinen Anmeldedaten einloggen"; +"bwi_mobile_dialog_m_more_button" = "Neue App herunterladen"; +"bwi_mobile_dialog_m_more_success" = "Benutzername kopiert"; diff --git a/Riot/Assets/en.lproj/Bwi.strings b/Riot/Assets/en.lproj/Bwi.strings index b5bbae092..5f84537b4 100644 --- a/Riot/Assets/en.lproj/Bwi.strings +++ b/Riot/Assets/en.lproj/Bwi.strings @@ -661,8 +661,27 @@ "room_error_join_failed_federation_disabled_message" = "You cannot join the room. The federation for this room has been withdrawn."; // MARK: migration to new client +// Banner "bwi_mobile_dialog_m_banner_title" = "Change to BundesMessengerX"; "bwi_mobileMdialog_m1_banner_text" = "This is a new technically optimized app from BuM. You can try it out now before everyone has to switch soon."; "bwi_mobileMdialog_m1_banner_text_bold" = " All your contacts and messages will be retained."; "bwi_mobile_dialog_m_banner_button2" = "Learn more"; "bwi_mobile_dialog_m_banner_button1" = "Remember later"; + +// Sheet page 1 +"bwi_mobile_dialog_m_more_title" = "BundesMessengerX"; +"bwi_mobile_dialog_m1_more_text_1" = "This app will soon be shut down and replaced by a new technically optimized app "; +"bwi_mobile_dialog_m1_more_text_2" = "(all your contacts and messages will remain)."; +"bwi_mobile_dialog_m1_more_text_3" = "\n\nAmong other things, you can expect:"; +"bwi_mobile_dialog_m1_more_text_bullet_1" = "faster performance"; +"bwi_mobile_dialog_m1_more_text_bullet_2" = "improved design"; +"bwi_mobile_dialog_m1_more_text_bullet_3" = "new functions, such as pinning messages"; +"bwi_mobile_dialog_m1_more_text_bullet_4" = "optimized accessibility"; + +// Sheet page 2 +"bwi_mobile_dialog_m_more2_title" = "Change now:"; +"bwi_mobile_dialog_m_more2_text_1" = "Copy user name here"; +"bwi_mobile_dialog_m_more2_text_2" = "Download app via the button"; +"bwi_mobile_dialog_m_more2_text_3" = "Log in with your credentials"; +"bwi_mobile_dialog_m_more_button" = "Download new app"; +"bwi_mobile_dialog_m_more_success" = "user name copied"; diff --git a/Riot/Generated/BWIStrings.swift b/Riot/Generated/BWIStrings.swift index 9ffc649cb..98322363f 100644 --- a/Riot/Generated/BWIStrings.swift +++ b/Riot/Generated/BWIStrings.swift @@ -299,6 +299,34 @@ public class BWIL10n: NSObject { public static var bwiMdmLogoutMessage: String { return BWIL10n.tr("Bwi", "bwi_mdm_logout_message") } + /// Diese App wird bald abgeschaltet und durch eine neue technisch optimierte App ersetzt + public static var bwiMobileDialogM1MoreText1: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_1") + } + /// (alle deine Kontakte und Nachrichten bleiben erhalten). + public static var bwiMobileDialogM1MoreText2: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_2") + } + /// \n\nDich erwartet u.a.: + public static var bwiMobileDialogM1MoreText3: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_3") + } + /// schnellere Performance + public static var bwiMobileDialogM1MoreTextBullet1: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_bullet_1") + } + /// verbessertes Design + public static var bwiMobileDialogM1MoreTextBullet2: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_bullet_2") + } + /// neue Funktionen, wie Nachrichten anheften + public static var bwiMobileDialogM1MoreTextBullet3: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_bullet_3") + } + /// optimierte Barrierefreiheit + public static var bwiMobileDialogM1MoreTextBullet4: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m1_more_text_bullet_4") + } /// Später erinnern public static var bwiMobileDialogMBannerButton1: String { return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_banner_button1") @@ -311,6 +339,34 @@ public class BWIL10n: NSObject { public static var bwiMobileDialogMBannerTitle: String { return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_banner_title") } + /// Benutzername hier kopieren + public static var bwiMobileDialogMMore2Text1: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more2_text_1") + } + /// App über den Button herunterladen + public static var bwiMobileDialogMMore2Text2: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more2_text_2") + } + /// Mit deinen Anmeldedaten einloggen + public static var bwiMobileDialogMMore2Text3: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more2_text_3") + } + /// Wechsel jetzt: + public static var bwiMobileDialogMMore2Title: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more2_title") + } + /// Neue App herunterladen + public static var bwiMobileDialogMMoreButton: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more_button") + } + /// Benutzername kopiert + public static var bwiMobileDialogMMoreSuccess: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more_success") + } + /// BundesMessengerX + public static var bwiMobileDialogMMoreTitle: String { + return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_more_title") + } /// Das ist eine neue, technisch optimierte App vom BuM. Du kannst sie jetzt schon ausprobieren, bevor bald alle umsteigen müssen. public static var bwiMobileMdialogM1BannerText: String { return BWIL10n.tr("Bwi", "bwi_mobileMdialog_m1_banner_text") diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 375895ffe..6c84218e5 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -411,6 +411,7 @@ internal class Asset: NSObject { @objc(AssetSharedImages) internal class SharedImages: NSObject { internal static let cancel = ImageAsset(name: "cancel") internal static let e2eVerified = ImageAsset(name: "e2e_verified") + internal static let bumxLogo = ImageAsset(name: "bumx_logo") internal static let horizontalLogo = ImageAsset(name: "horizontal_logo") internal static let loginFlowLogo = ImageAsset(name: "login_flow_logo") internal static let radioButtonDefault = ImageAsset(name: "radio-button-default") diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index 712d626f5..1f6644d15 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -1894,7 +1894,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou MXSession* session = [self mxSession]; if(!session) return; - FeatureBannerVisibilityService *featureBannerService = [[FeatureBannerVisibilityService alloc] initWithMxSession:session]; + FeatureBannerVisibilityService *featureBannerService = [FeatureBannerVisibilityService alloc]; [featureBannerService isUnreadWithCompletion: ^(BOOL unread) { if (unread) { // this notification will be called either if the user clicked on the banner or wants to hide it @@ -1932,7 +1932,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou MXSession* session = [self mxSession]; if(!session) return; - FeatureBannerVisibilityService *featureBannerService = [[FeatureBannerVisibilityService alloc] initWithMxSession:session]; + FeatureBannerVisibilityService *featureBannerService = [FeatureBannerVisibilityService alloc]; [featureBannerService markAsRead]; self->shouldHideFeatureBanner = TRUE; [self.delegate dataSource:self didCellChange:nil]; diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index 6b8ccbcfb..b27dc860a 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -772,6 +772,11 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { self.currentMatrixSession?.refreshHomeserverWellknown(false, success: { wellknown in // bwi: #5706 fix crash: only show matomo alert when wellknown is available wellknown?.updateFederationStatus() + // BWI #7564 add migration level + if let migrationLevel = wellknown?.migrationInfoLevel() { + BWIBuildSettings.shared.BuMXMigrationInfoLevel = migrationLevel + } + // BWI #7564 END self.bwiCheckForMatomoPromt() }, failure: nil) } diff --git a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift index 3dfae2391..bc3c597ce 100644 --- a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift +++ b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift @@ -250,7 +250,11 @@ class AuthenticationService: NSObject { if let wellKnown = try? await wellKnown(for: homeserverURL) { self.wellknown = wellKnown wellknown?.updateFederationStatus() - + // BWI #7564 add migration level + if let migrationLevel = wellknown?.migrationInfoLevel() { + BWIBuildSettings.shared.BuMXMigrationInfoLevel = migrationLevel + } + // BWI #7564 END if let baseURL = URL(string: wellKnown.homeServer.baseUrl) { homeserverURL = baseURL } diff --git a/bwi/DeveloperSettings/DeveloperSettingsView.swift b/bwi/DeveloperSettings/DeveloperSettingsView.swift index 16aff2aca..ec17137b6 100644 --- a/bwi/DeveloperSettings/DeveloperSettingsView.swift +++ b/bwi/DeveloperSettings/DeveloperSettingsView.swift @@ -229,15 +229,11 @@ fileprivate func unrestrictUser(mxSession: MXSession?) -> Bool { return true } -fileprivate func unmarkBannerVersion(mxSession: MXSession?) -> Bool { - guard let mxSession = mxSession else { - return false - } - +fileprivate func unmarkBannerVersion(mxSession: MXSession?) -> Bool { // NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { - _ = FeatureBannerVisibilityService(mxSession: mxSession).markAsUnread(version: version) + FeatureBannerVisibilityService().markAsUnread(version: version) } return true diff --git a/bwi/FeatureBanner/FeatureBannerView.swift b/bwi/FeatureBanner/FeatureBannerView.swift index c073cb2f1..296802e0a 100644 --- a/bwi/FeatureBanner/FeatureBannerView.swift +++ b/bwi/FeatureBanner/FeatureBannerView.swift @@ -90,8 +90,10 @@ protocol FeatureBannerDelegate { } func didPressShowDetails() { - hideTopBanner() - // Show Details + let migrationInfoView = MigrationInfoView().interactiveDismissDisabled(true) + let hostingViewController = UIHostingController(rootView: migrationInfoView) + hostingViewController.modalPresentationStyle = .popover + hostingController.parent?.present(hostingViewController, animated: true, completion: nil) } @objc func closeModal() { @@ -169,7 +171,7 @@ struct FeatureBannerView: View { .font(.system(size: 18)) .bold() .padding(10) - .foregroundColor(Color(ThemeService.shared().theme.tintColor)) + .foregroundColor(ThemeService.shared().isCurrentThemeDark() ? Color(ThemeService.shared().theme.tintColor) : Color.black) Spacer() } } diff --git a/bwi/FeatureBanner/MigrationInfoView.swift b/bwi/FeatureBanner/MigrationInfoView.swift new file mode 100644 index 000000000..c505c644a --- /dev/null +++ b/bwi/FeatureBanner/MigrationInfoView.swift @@ -0,0 +1,243 @@ +// +/* + * 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 + + var body: some View { + TabView(selection: $selectedTab) { + MigrationInfoViewOne() + .tag(1) + MigrationInfoViewTwo() + .tag(2) + } + .tabViewStyle(.page) + .indexViewStyle(.page(backgroundDisplayMode: .always)) + //.background(Color.white.ignoresSafeArea()) + .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.shared().theme.tintColor)) + .padding(20) + } + } + Spacer() + HStack() { + Button { + withAnimation { + selectedTab = 1 + } + } label: { + Image(systemName: "arrow.left") + .resizable() + .frame(width: 24, height: 24) + .foregroundStyle(Color(ThemeService.shared().theme.tintColor)) + } + .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.shared().theme.tintColor)) + } + .padding(EdgeInsets(top: 20, leading: 30, bottom: 10, trailing: 30)) + .opacity(selectedTab == 2 ? 0 : 1) + } + } + } + } +} + + +// MARK: Migraion Info View one +struct MigrationInfoViewOne: View { + var body: some View { + GeometryReader { geo in + ScrollView(.vertical) { + VStack(alignment: .center, spacing: 30) { + + Spacer() + + header + + infoText + + Spacer() + + } + .frame(width: geo.size.width, height: geo.size.height) + } + } + } + + var header: some View { + VStack(spacing: 50) { + Image("bumx_logo") + .resizable() + .frame(width: 150, height: 150) + .clipShape(.rect(cornerRadius: 26)) + .overlay( + RoundedRectangle(cornerRadius: 26) + .stroke(.gray, lineWidth: 0.4) + ) + Text(BWIL10n.bwiMobileDialogMMoreTitle) + .font(.title) + .bold() + } + } + + var infoText: some View { + VStack(alignment: .leading) { + Text(BWIL10n.bwiMobileDialogM1MoreText1) + + 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: 0, leading: 30, bottom: 0, trailing: 30)) + } +} + + +// MARK: Migraion Info View two +struct MigrationInfoViewTwo: View { + + var body: some View { + GeometryReader { geo in + ScrollView(.vertical) { + VStack(alignment: .center, spacing: 30) { + + Spacer() + + header + + instructionsList + + Spacer() + + downloadNewAppButton + } + .frame(width: geo.size.width, height: geo.size.height) + } + } + } + + var header: some View { + VStack(spacing: 50) { + Image("bumx_logo") + .resizable() + .frame(width: 150, height: 150) + .clipShape(.rect(cornerRadius: 26)) + .overlay( + RoundedRectangle(cornerRadius: 26) + .stroke(.gray, lineWidth: 0.4) + ) + Text(BWIL10n.bwiMobileDialogMMore2Title) + .font(.title) + .bold() + } + } + + var instructionsList: some View { + VStack(alignment: .leading, spacing: 10) { + HStack() { + Text("1.") + Button(action: { + + }, label: { + Text(BWIL10n.bwiMobileDialogMMore2Text1) + .underline() + Image(systemName: "square.on.square") + .resizable() + .frame(width: 15, height: 15) + }) + } + HStack() { + Text("2.") + Text(BWIL10n.bwiMobileDialogMMore2Text2) + } + HStack() { + Text("3.") + Text(BWIL10n.bwiMobileDialogMMore2Text3) + } + } + .lineLimit(nil) + .fixedSize(horizontal: false, vertical: true) + } + + 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(.white) + .padding(.vertical, 10) + .padding(.horizontal, 50) + .background(Color(ThemeService.shared().theme.tintColor)) + .clipShape(RoundedRectangle(cornerRadius: 10)) + .lineLimit(nil) + .fixedSize(horizontal: false, vertical: true) + }) + .padding(.bottom, 100) + } +} diff --git a/bwi/TopBanner/FeatureBannerViewController.swift b/bwi/TopBanner/FeatureBannerViewController.swift index 621453777..f24d62a90 100644 --- a/bwi/TopBanner/FeatureBannerViewController.swift +++ b/bwi/TopBanner/FeatureBannerViewController.swift @@ -43,7 +43,7 @@ import UIKit override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - FeatureBannerVisibilityService(mxSession: self.session).markAsRead() + FeatureBannerVisibilityService().markAsRead() NotificationCenter.default.post(name: .bwiMarkTopBannerAsRead, object: self, userInfo: ["type" : "feature_banner"]) } diff --git a/bwi/TopBanner/FeatureBannerVisibilityService.swift b/bwi/TopBanner/FeatureBannerVisibilityService.swift index 838f23e33..d840af96c 100644 --- a/bwi/TopBanner/FeatureBannerVisibilityService.swift +++ b/bwi/TopBanner/FeatureBannerVisibilityService.swift @@ -29,12 +29,6 @@ import Foundation static let featureVisibility = "de.bwi.should_show_ios_release_notes" } - private let session:MXSession - - init(mxSession: MXSession) { - self.session = mxSession - } - func markAsRead() { BWIBuildSettings.shared.didShowBuMXMigrationInfoLevel = BWIBuildSettings.shared.BuMXMigrationInfoLevel }