diff --git a/Config/BWIBuildSettings.swift b/Config/BWIBuildSettings.swift
index 02ec6f2b0..3b07bf08e 100644
--- a/Config/BWIBuildSettings.swift
+++ b/Config/BWIBuildSettings.swift
@@ -38,6 +38,8 @@ class BWIBuildSettings: NSObject {
static let additionalBwiHeaderKey = "bwiHeader"
static let isWellknownFederationEnabled = "isWellknownFederationEnabled"
static let isLabsFederationEnabled = "isLabsFederationEnabled"
+ static let BuMXMigrationInfoLevelKey = "BuMXMigrationInfoLevel"
+ static let didBuMXMigrationInfoLevelKey = "didBuMXMigrationInfoLevel"
}
private struct BwiSettingsConstants {
@@ -488,7 +490,7 @@ class BWIBuildSettings: NSObject {
var forgotPasswordInformationAlert = true
// MARK: Promote new feature within a banner below the navigation view
- var showTopBanner = false
+ var showTopBanner = true
var showCustomServerDisplayName = true
var customServerDisplayName = ""
@@ -674,6 +676,15 @@ class BWIBuildSettings: NSObject {
@UserDefault(key: UserDefaultsKeys.isLabsFederationEnabled, defaultValue: false, storage: RiotSettings.defaults)
var isLabsFederationEnabled
+ // Migration status from wellknown config
+ @UserDefault(key: UserDefaultsKeys.BuMXMigrationInfoLevelKey, defaultValue: 0, storage: RiotSettings.defaults)
+ var BuMXMigrationInfoLevel
+
+ // Migration level already shown
+ @UserDefault(key: UserDefaultsKeys.didBuMXMigrationInfoLevelKey, defaultValue: 0, storage: RiotSettings.defaults)
+ var didShowBuMXMigrationInfoLevel
+
+
// shows the grey/green/red shield for the room avatar / user avatar
var showEncryptionStatusBadgeOnAvatar = false
diff --git a/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Apple iPhone.svg b/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Apple iPhone.svg
new file mode 100644
index 000000000..a46131564
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Apple iPhone.svg
@@ -0,0 +1,9 @@
+
diff --git a/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Contents.json
new file mode 100644
index 000000000..33469fecf
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/migration_detail_1.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "Apple iPhone.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
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 982420c10..e8e8df2e3 100644
--- a/Riot/Assets/de.lproj/Bwi.strings
+++ b/Riot/Assets/de.lproj/Bwi.strings
@@ -747,6 +747,35 @@
"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";
+
+"bwi_a11y_close_button" = "Ansicht schließen";
+
// MARK owner handling
"room_member_power_level_owner_in" = "Inhaber von %@";
"room_member_power_level_short_owner" = "Inhaber";
diff --git a/Riot/Assets/en.lproj/Bwi.strings b/Riot/Assets/en.lproj/Bwi.strings
index 29ecb4cf5..6ea85f761 100644
--- a/Riot/Assets/en.lproj/Bwi.strings
+++ b/Riot/Assets/en.lproj/Bwi.strings
@@ -660,6 +660,34 @@
"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";
+
+"bwi_a11y_close_button" = "Close window";
+
// MARK owner handling
"room_member_power_level_owner_in" = "Owner in %@";
"room_member_power_level_short_owner" = "Owner";
diff --git a/Riot/Generated/BWIStrings.swift b/Riot/Generated/BWIStrings.swift
index 8d7040374..5faff94c8 100644
--- a/Riot/Generated/BWIStrings.swift
+++ b/Riot/Generated/BWIStrings.swift
@@ -131,6 +131,10 @@ public class BWIL10n: NSObject {
public static var bumAutheticationTitle: String {
return BWIL10n.tr("Bwi", "bum_authetication_title")
}
+ /// Ansicht schließen
+ public static var bwiA11yCloseButton: String {
+ return BWIL10n.tr("Bwi", "bwi_a11y_close_button")
+ }
/// Barrierefreiheitserklärung
public static var bwiAccessibilityDeclarationButtonTitle: String {
return BWIL10n.tr("Bwi", "bwi_accessibility_declaration_button_title")
@@ -299,6 +303,82 @@ 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")
+ }
+ /// Erfahre mehr
+ public static var bwiMobileDialogMBannerButton2: String {
+ return BWIL10n.tr("Bwi", "bwi_mobile_dialog_m_banner_button2")
+ }
+ /// Wechsel zum BundesMessengerX
+ 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")
+ }
+ /// Alle deine Kontakte und Nachrichten bleiben erhalten.
+ public static var bwiMobileMdialogM1BannerTextBold: String {
+ return BWIL10n.tr("Bwi", "bwi_mobileMdialog_m1_banner_text_bold")
+ }
/// Meine Notizen
public static var bwiNotesRoomTitle: String {
return BWIL10n.tr("Bwi", "bwi_notes_room_title")
diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift
index 375895ffe..c3989cea8 100644
--- a/Riot/Generated/Images.swift
+++ b/Riot/Generated/Images.swift
@@ -63,6 +63,7 @@ internal class Asset: NSObject {
internal static let introduceFederation2Light = ImageAsset(name: "introduce_federation_2_light")
internal static let introduceFederation3 = ImageAsset(name: "introduce_federation_3")
internal static let mediaFileUnavailable = ImageAsset(name: "media_file_unavailable")
+ internal static let migrationDetail1 = ImageAsset(name: "migration_detail_1")
internal static let newFeatures = ImageAsset(name: "new_features")
internal static let qr = ImageAsset(name: "qr")
internal static let qrcodeViewfinder = ImageAsset(name: "qrcode_viewfinder")
@@ -411,6 +412,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 725965e62..1f6644d15 100644
--- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
+++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
@@ -202,7 +202,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou
{
NSMutableArray *types = [NSMutableArray array];
// bwi: add new feature banner
- if (!shouldHideFeatureBanner && BWIBuildSettings.shared.showTopBanner && BWIBuildSettings.shared.isWellknownFederationEnabled){
+ if (!shouldHideFeatureBanner && BWIBuildSettings.shared.showTopBanner && BWIBuildSettings.shared.BuMXMigrationInfoLevel > 0) {
[types addObject:@(RecentsDataSourceSectionTypeFeatureBanner)];
}
@@ -1890,17 +1890,18 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou
- (void) shouldShowFeatureBanner
{
- if (BWIBuildSettings.shared.showTopBanner && BWIBuildSettings.shared.isWellknownFederationEnabled){
+ if (BWIBuildSettings.shared.showTopBanner && BWIBuildSettings.shared.BuMXMigrationInfoLevel > 0){
MXSession* session = [self mxSession];
if(!session)
return;
- NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
- FeatureBannerVisibilityService *featureBannerService = [[FeatureBannerVisibilityService alloc] initWithMxSession:session];
- [featureBannerService isUnreadWithVersion:version completion:^(BOOL unread) {
+ 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
[[NSNotificationCenter defaultCenter] addObserverForName:@"de.bwi.messenger.hide_top_banner" object:NULL queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
- [self markFeatureBannerAsRead];
+ self->shouldHideFeatureBanner = TRUE;
+ [self.delegate dataSource:self didCellChange:nil];
+ //[self markFeatureBannerAsRead];
}];
// this notification will be called either if the user clicked on the banner or wants to hide it using a swipe gesture
@@ -1931,9 +1932,8 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou
MXSession* session = [self mxSession];
if(!session)
return;
- NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
- FeatureBannerVisibilityService *featureBannerService = [[FeatureBannerVisibilityService alloc] initWithMxSession:session];
- [featureBannerService markAsReadWithVersion:version];
+ 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/Riot/Modules/Home/AllChats/AllChatsViewController.swift b/Riot/Modules/Home/AllChats/AllChatsViewController.swift
index 8490e9fd5..3e4b3fcc7 100644
--- a/Riot/Modules/Home/AllChats/AllChatsViewController.swift
+++ b/Riot/Modules/Home/AllChats/AllChatsViewController.swift
@@ -621,10 +621,15 @@ class AllChatsViewController: HomeViewController {
}
// bwi: feature banner cell
if sectionType == .featureBanner {
+ var username = ""
+ if let mainSession = self.mainSession {
+ username = mainSession.myUser.displayname
+ }
guard let cell = tableView.dequeueReusableCell(withIdentifier: "featureBanner", for: indexPath) as? FeatureBannerViewCell else {
return UITableViewCell()
}
cell.selectionStyle = .none
+ cell.setUsername(username: username)
cell.setupView(parent: self, rootView: FeatureBannerView(delegate: cell))
featureBannerViewHeight = cell.calculateHeight()
return cell
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 8362b2e11..0a259070e 100644
--- a/bwi/FeatureBanner/FeatureBannerView.swift
+++ b/bwi/FeatureBanner/FeatureBannerView.swift
@@ -28,6 +28,7 @@ protocol FeatureBannerDelegate {
private var parentViewController: UIViewController?
private let hostingController = UIHostingController(rootView: nil)
private var webViewController: WebViewViewController?
+ private var username: String = ""
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
@@ -90,62 +91,69 @@ protocol FeatureBannerDelegate {
}
func didPressShowDetails() {
- let htmlFile = BWIBuildSettings.shared.bwiFeatureHistoryFilePath
- self.webViewController = WebViewViewController(localHTMLFile: htmlFile)
- webViewController?.title = BWIL10n.bwiSettingsNewFeaturesHeader
- let navigationBar: UINavigationController = UINavigationController(rootViewController: webViewController!)
- webViewController?.navigationItem.setLeftBarButton(UIBarButtonItem(title: VectorL10n.close, style: .plain, target: self, action: #selector(closeModal)), animated: false)
- hostingController.parent?.present(navigationBar, animated: true, completion: { () -> Void in
- self.hideTopBanner()
- })
+ let migrationInfoView = MigrationInfoView(username: username).environmentObject(BWIThemeService.shared).interactiveDismissDisabled(true)
+ let hostingViewController = UIHostingController(rootView: migrationInfoView)
+ if hostingViewController.popoverPresentationController != nil {
+ hostingViewController.modalPresentationStyle = .popover
+ }
+ hostingController.parent?.present(hostingViewController, animated: true, completion: nil)
}
@objc func closeModal() {
webViewController?.dismiss(animated: true)
}
+
+ func setUsername(username: String) {
+ self.username = username
+ }
}
struct FeatureBannerView: View {
var delegate: FeatureBannerDelegate?
+ let darkmodeBackground = UIColor(rgb:0x2394A7)
var body: some View {
VStack(alignment: .center) {
- closeButton
header
advertisementText
- if !BWIL10n.bwiFeatureBannerShowMoreButton.isEmpty {
+ HStack(alignment: .center, spacing: 12) {
+ remindMeLaterButton
showMoreButton
- } else {
- Spacer()
- .frame(height: 25)
}
}
- .background(Color(ThemeService.shared().theme.tintColor))
+ .padding(.horizontal, 12)
+ .background(ThemeService.shared().isCurrentThemeDark() ? Color(uiColor: darkmodeBackground) : Color(ThemeService.shared().theme.tintColor))
.cornerRadius(12)
.padding(16)
}
var header: some View {
HStack() {
-// Image(Asset.Images.newFeatures.name)
- Image(Asset.Images.roomFederatedBumIconDark.name)
+ Image(Asset.Images.newFeatures.name)
// .renderingMode(.template)
-// .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
- Text(BWIL10n.bwiFeatureBannerHeader)
+ .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
+ .accessibilityHidden(true)
+ Text(BWIL10n.bwiMobileDialogMBannerTitle)
.font(.system(size: 20).bold())
.foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
+ Spacer()
}
+ .padding(.top, 16)
}
var advertisementText: some View {
- Text(BWIL10n.bwiFeatureBannerAdvertisementText)
- .font(.system(size: 15))
- .multilineTextAlignment(.center)
- .lineLimit(nil)
- .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
- .padding(5)
+ VStack {
+ Text(BWIL10n.bwiMobileMdialogM1BannerText) +
+ Text(BWIL10n.bwiMobileMdialogM1BannerTextBold)
+ .bold()
+ }
+ .font(.system(size: 15))
+ .multilineTextAlignment(.leading)
+ .lineLimit(nil)
+ .fixedSize(horizontal: false, vertical: true)
+ .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
}
var closeButton: some View {
@@ -166,13 +174,37 @@ struct FeatureBannerView: View {
Button {
delegate?.didPressShowDetails()
} label: {
- Text(BWIL10n.bwiFeatureBannerShowMoreButton)
- .font(.system(size: 15))
- .padding(10)
- .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
- .overlay(RoundedRectangle(cornerRadius: 12)
- .stroke(Color(ThemeService.shared().theme.backgroundColor), lineWidth: 2))
+ HStack() {
+ Spacer()
+ Text(BWIL10n.bwiMobileDialogMBannerButton2)
+ .font(.system(size: 18))
+ .bold()
+ .padding(10)
+ .foregroundColor(ThemeService.shared().isCurrentThemeDark() ? Color(uiColor: darkmodeBackground) : Color.black)
+ Spacer()
+ }
}
+ .background(Color(ThemeService.shared().theme.backgroundColor))
+ .cornerRadius(12)
+ .padding(.top, 10)
+ .padding(.bottom, 25)
+ }
+
+ var remindMeLaterButton: some View {
+ Button {
+ delegate?.didPressClose()
+ } label: {
+ HStack() {
+ Spacer()
+ Text(BWIL10n.bwiMobileDialogMBannerButton1)
+ .font(.system(size: 18))
+ .padding(10)
+ .foregroundColor(Color(ThemeService.shared().theme.backgroundColor))
+ Spacer()
+ }
+ }
+ .overlay(RoundedRectangle(cornerRadius: 12)
+ .stroke(Color(ThemeService.shared().theme.backgroundColor), lineWidth: 2))
.padding(.top, 10)
.padding(.bottom, 25)
}
diff --git a/bwi/FeatureBanner/MigrationInfoView.swift b/bwi/FeatureBanner/MigrationInfoView.swift
new file mode 100644
index 000000000..62e6e2b0b
--- /dev/null
+++ b/bwi/FeatureBanner/MigrationInfoView.swift
@@ -0,0 +1,313 @@
+//
+/*
+ * 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()
+
+ let username: String
+
+ var body: some View {
+ TabView(selection: $selectedTab) {
+ MigrationInfoViewOne()
+ .tag(1)
+ MigrationInfoViewTwo(username: username)
+ .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.bwiA11yCloseButton)
+ }
+ 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)
+ }
+ }
+ }
+ .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)
+
+ 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: 10, leading: 30, bottom: 0, trailing: 30))
+ .accessibilityElement(children: .ignore)
+ .accessibilityLabel(
+ BWIL10n.bwiMobileDialogMMoreTitle + ". " +
+ BWIL10n.bwiMobileDialogM1MoreText1 +
+ BWIL10n.bwiMobileDialogM1MoreText2 +
+ BWIL10n.bwiMobileDialogM1MoreText3 + ", " +
+ BWIL10n.bwiMobileDialogM1MoreTextBullet1 + ", " +
+ BWIL10n.bwiMobileDialogM1MoreTextBullet2 + ", " +
+ BWIL10n.bwiMobileDialogM1MoreTextBullet3 + ", " +
+ BWIL10n.bwiMobileDialogM1MoreTextBullet4)
+ }
+}
+
+
+// MARK: Migraion Info View two
+struct MigrationInfoViewTwo: View {
+ let username: String
+ @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)
+
+ }
+ .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 = username
+ 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)
+ }
+}
diff --git a/bwi/TopBanner/FeatureBannerViewController.swift b/bwi/TopBanner/FeatureBannerViewController.swift
index 3843908f9..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(version: self.version)
+ 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 81d5b0d3e..d840af96c 100644
--- a/bwi/TopBanner/FeatureBannerVisibilityService.swift
+++ b/bwi/TopBanner/FeatureBannerVisibilityService.swift
@@ -29,45 +29,26 @@ 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
}
- func markAsRead( version: String ) -> MXHTTPOperation? {
- // Update only the "widgets" field in the account data
- var featureDict = self.session.accountData.accountData(forEventType: AccountDataTypes.featureVisibility) ?? [:]
+ func markAsUnread( version: String ) {
+ BWIBuildSettings.shared.didShowBuMXMigrationInfoLevel = 0
+ }
+
+ func isUnread(completion: @escaping (_ unread : Bool) -> Void) {
+ guard BWIBuildSettings.shared.BuMXMigrationInfoLevel < 3 else {
+ completion(true)
+ return
+ }
- featureDict[version] = false
-
- return session.setAccountData(featureDict, forType: AccountDataTypes.featureVisibility, success: nil, failure: nil)
- }
-
- func markAsUnread( version: String ) -> MXHTTPOperation? {
- // Update only the "widgets" field in the account data
- var featureDict = self.session.accountData.accountData(forEventType: AccountDataTypes.featureVisibility) ?? [:]
-
- featureDict[version] = true
-
- return session.setAccountData(featureDict, forType: AccountDataTypes.featureVisibility, success: {
- // bwi: update tableview
- NotificationCenter.default.post(name: .bwiMarkTopBannerAsUnRead, object: nil, userInfo: ["type" : "feature_banner"])
- }, failure: nil)
- }
-
- func isUnread( version: String, completion: @escaping (_ unread : Bool) -> Void) {
- session.matrixRestClient.getAccountData(forType: AccountDataTypes.featureVisibility ) { (jsonResponse, error) in
-
- guard let featureDict = jsonResponse as? [String:Any] else {
- completion(true)
- return
- }
- guard let unread = featureDict[version] as? Bool else {
- completion(true)
- return
- }
- completion(unread)
+ if BWIBuildSettings.shared.didShowBuMXMigrationInfoLevel < BWIBuildSettings.shared.BuMXMigrationInfoLevel {
+ completion(true)
+ return
+ } else {
+ completion(false)
+ return
}
}
}
diff --git a/bwi/Wellknown/Wellknown+Bwi.swift b/bwi/Wellknown/Wellknown+Bwi.swift
index beb38b7e1..6981b7080 100644
--- a/bwi/Wellknown/Wellknown+Bwi.swift
+++ b/bwi/Wellknown/Wellknown+Bwi.swift
@@ -94,6 +94,24 @@ public extension MXWellKnown {
}
}
+ @objc func migrationInfoLevel() -> Int {
+ do {
+ guard let bwiDict = self.jsonDictionary()["de.bwi"] as? [String : Any] else {
+ return 0
+ }
+
+ let bwi = try WellknownBWI(dict: bwiDict)
+ if let migration = bwi.migrationBuMX {
+ return migration.level ?? 0
+ } else {
+ return 0
+ }
+ }
+ catch {
+ return 0
+ }
+ }
+
@objc func updateFederationStatus() {
do {
guard let bwiDict = self.jsonDictionary()["de.bwi"] as? [String : Any] else {
diff --git a/bwi/Wellknown/WellknownBWI.swift b/bwi/Wellknown/WellknownBWI.swift
index ce4626140..453fea626 100644
--- a/bwi/Wellknown/WellknownBWI.swift
+++ b/bwi/Wellknown/WellknownBWI.swift
@@ -21,6 +21,7 @@ struct WellknownBWI: Decodable {
let dataPrivacyURL: String?
let imprintURL: String?
let federation: WellknownFederation?
+ let migrationBuMX: WellknownMigrationBuMX?
init(dict: [String: Any]) throws {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
@@ -32,6 +33,7 @@ struct WellknownBWI: Decodable {
case dataPrivacyURL = "data_privacy_url"
case imprintURL = "imprint_url"
case federation
+ case migrationBuMX = "migration_bumx"
}
}
@@ -52,3 +54,11 @@ struct WellknownFederation: Decodable {
}
}
+
+struct WellknownMigrationBuMX: Decodable {
+ let level: Int?
+
+ enum CodingKeys: String, CodingKey {
+ case level
+ }
+}