feat: add migration part 1 banner (MESSENGER-7564)

This commit is contained in:
Jan Niklas Grabowski
2025-09-15 17:39:24 +02:00
parent b819783abf
commit 00d9048124
10 changed files with 148 additions and 67 deletions
+12 -1
View File
@@ -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
+7
View File
@@ -746,3 +746,10 @@
"introduce_federation_start" = "Verstanden";
"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
"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";
+7
View File
@@ -659,3 +659,10 @@
"introduce_federation_start" = "Understood";
"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
"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";
+20
View File
@@ -299,6 +299,26 @@ public class BWIL10n: NSObject {
public static var bwiMdmLogoutMessage: String {
return BWIL10n.tr("Bwi", "bwi_mdm_logout_message")
}
/// 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")
}
/// 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")
@@ -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) {
[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];
[featureBannerService markAsRead];
self->shouldHideFeatureBanner = TRUE;
[self.delegate dataSource:self didCellChange:nil];
}
+50 -29
View File
@@ -90,14 +90,8 @@ 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()
})
hideTopBanner()
// Show Details
}
@objc func closeModal() {
@@ -111,17 +105,15 @@ struct FeatureBannerView: View {
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)
}
}
.padding(.horizontal, 12)
.background(Color(ThemeService.shared().theme.tintColor))
.cornerRadius(12)
.padding(16)
@@ -129,23 +121,28 @@ struct FeatureBannerView: View {
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))
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 +163,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(Color(ThemeService.shared().theme.tintColor))
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: 15))
.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)
}
@@ -43,7 +43,7 @@ import UIKit
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
_ = FeatureBannerVisibilityService(mxSession: self.session).markAsRead(version: self.version)
FeatureBannerVisibilityService(mxSession: self.session).markAsRead()
NotificationCenter.default.post(name: .bwiMarkTopBannerAsRead, object: self, userInfo: ["type" : "feature_banner"])
}
@@ -35,39 +35,26 @@ import Foundation
self.session = mxSession
}
func markAsRead( version: String ) -> MXHTTPOperation? {
// Update only the "widgets" field in the account data
var featureDict = self.session.accountData.accountData(forEventType: AccountDataTypes.featureVisibility) ?? [:]
featureDict[version] = false
return session.setAccountData(featureDict, forType: AccountDataTypes.featureVisibility, success: nil, failure: nil)
func markAsRead() {
BWIBuildSettings.shared.didShowBuMXMigrationInfoLevel = BWIBuildSettings.shared.BuMXMigrationInfoLevel
}
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 markAsUnread( version: String ) {
BWIBuildSettings.shared.didShowBuMXMigrationInfoLevel = 0
}
func isUnread( version: String, completion: @escaping (_ unread : Bool) -> Void) {
session.matrixRestClient.getAccountData(forType: AccountDataTypes.featureVisibility ) { (jsonResponse, error) in
func isUnread(completion: @escaping (_ unread : Bool) -> Void) {
guard BWIBuildSettings.shared.BuMXMigrationInfoLevel < 3 else {
completion(true)
return
}
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
}
}
}
+18
View File
@@ -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 {
+10
View File
@@ -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
}
}