diff --git a/Config/BWIBuildSettings.swift b/Config/BWIBuildSettings.swift
index 2bb5cd468..5ba0acedd 100644
--- a/Config/BWIBuildSettings.swift
+++ b/Config/BWIBuildSettings.swift
@@ -727,4 +727,8 @@ class BWIBuildSettings: NSObject {
// MARK: Profile picture hint
// (only when federation is enabled)
var showChangeProfilePictureHint = false
+
+ // MARK: Federation Introduction
+ // (only when federation is enabled in the client and well-known flag is set)
+ var showFederationIntroduction = false
}
diff --git a/Config/BuM-Beta/BWIBuildSettings+BuM-Beta.swift b/Config/BuM-Beta/BWIBuildSettings+BuM-Beta.swift
index 53dc7c8e4..9623079a4 100644
--- a/Config/BuM-Beta/BWIBuildSettings+BuM-Beta.swift
+++ b/Config/BuM-Beta/BWIBuildSettings+BuM-Beta.swift
@@ -38,7 +38,8 @@ extension BWIBuildSettings {
ignoreBlockingMaintenance = true
bwiUseWellKnownPrivacyPolicyLink = true
showChangeProfilePictureHint = true
-
+ showFederationIntroduction = true
+
itunesAppLink = "https://apps.apple.com/de/app/bundesmessenger/id1616866351"
avoidServerSelectionOnAppConfig = true
enableFeatureWYSIWYGByDefault = true
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_dark.imageset/Contents.json
new file mode 100644
index 000000000..a19a54922
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_dark.imageset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_light.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_light.imageset/Contents.json
new file mode 100644
index 000000000..6fe332016
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_1_light.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Contents.json
new file mode 100644
index 000000000..b78772d84
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "Kennzeichnung_BuM_dark_mobile.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "template-rendering-intent" : "original"
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Kennzeichnung_BuM_dark_mobile.svg b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Kennzeichnung_BuM_dark_mobile.svg
new file mode 100644
index 000000000..260a32857
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_dark.imageset/Kennzeichnung_BuM_dark_mobile.svg
@@ -0,0 +1,12 @@
+
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Contents.json
new file mode 100644
index 000000000..ee0238965
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "Kennzeichnung_BuM_light_mobile.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "template-rendering-intent" : "original"
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Kennzeichnung_BuM_light_mobile.svg b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Kennzeichnung_BuM_light_mobile.svg
new file mode 100644
index 000000000..c46be4fe7
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_2_light.imageset/Kennzeichnung_BuM_light_mobile.svg
@@ -0,0 +1,12 @@
+
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Apple iPhone 11 White (1).png b/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Apple iPhone 11 White (1).png
new file mode 100644
index 000000000..3b743cfda
Binary files /dev/null and b/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Apple iPhone 11 White (1).png differ
diff --git a/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Contents.json b/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Contents.json
new file mode 100644
index 000000000..c70125781
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/BWI/introduce_federation_3.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "Apple iPhone 11 White (1).png",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "template-rendering-intent" : "original"
+ }
+}
diff --git a/Riot/Assets/de.lproj/Bwi.strings b/Riot/Assets/de.lproj/Bwi.strings
index 4f8e9217c..65e4e3355 100644
--- a/Riot/Assets/de.lproj/Bwi.strings
+++ b/Riot/Assets/de.lproj/Bwi.strings
@@ -51,6 +51,9 @@
"bwi_settings_developer_restrict_user" = "Nutzer einschränken";
"bwi_settings_developer_unrestrict_user" = "Nutzereinschränkung aufheben";
"bwi_settings_developer_unmark_banner" = "Banner als nicht gelesen markieren";
+"bwi_settings_developer_introduce_federation" = "Föderation";
+"bwi_settings_developer_introduce_federation_preview" = "Vorschau zeigen";
+"bwi_settings_developer_introduce_federation_reset" = "Account Data Flag urücksetzen";
"bwi_settings_developer_well_known" = "Well-Known";
"bwi_settings_developer_capabilities" = "Capabilities";
"bwi_settings_developer_maintenance" = "Maintenance";
@@ -703,3 +706,11 @@
"room_participants_invite_prompt_server_acl_for_room_not_configured_text" = "Du kannst noch keine Personen aus einer föderierten Organisation einladen, da die Freigabe hierfür noch nicht erteilt wurde. Gib dem Admin Bescheid, dass die Einstellung getroffen werden muss.";
"room_participants_invite_prompt_server_acl_loading_error_text" = "Die Person kann aktuell nicht eingeladen werden, bitte versuche es später erneut.";
+"introduce_federation_screen1_title" = "Föderation";
+"introduce_federation_screen1_description" = "Übergreifende sichere Kommunikation zwischen verschiedenen Organisationen";
+"introduce_federation_screen2_title" = "Kennzeichnung";
+"introduce_federation_screen2_description" = "Föderierte Personen und Räume erkennst du am Symbol mit den zwei sich überschneidenden Kreisen.";
+"introduce_federation_screen3_title" = "Individuelle Einstellung";
+"introduce_federation_screen3_description" = "Bestimme als Admin, welche Räume für eine Föderation zugelassen sind.";
+"introduce_federation_start" = "Verstanden";
+
diff --git a/Riot/Assets/en.lproj/Bwi.strings b/Riot/Assets/en.lproj/Bwi.strings
index 07bfd376a..c762bd067 100644
--- a/Riot/Assets/en.lproj/Bwi.strings
+++ b/Riot/Assets/en.lproj/Bwi.strings
@@ -52,6 +52,9 @@
"bwi_settings_developer_restrict_user" = "Restrict user";
"bwi_settings_developer_unrestrict_user" = "Remove user restriction";
"bwi_settings_developer_unmark_banner" = "Unmark Feature Banner";
+"bwi_settings_developer_introduce_federation" = "Federation";
+"bwi_settings_developer_introduce_federation_preview" = "Show preview";
+"bwi_settings_developer_introduce_federation_reset" = "Reset account data flag";
"bwi_settings_developer_well_known" = "Well-Known";
"bwi_settings_developer_capabilities" = "Capabilities";
"bwi_settings_developer_maintenance" = "Maintenance";
@@ -616,3 +619,10 @@
"room_participants_invite_prompt_server_acl_for_room_not_configured_text" = "You cannot yet invite people from a federated organization, as this has not yet been approved. Let the admin know that the setting needs to be made.";
"room_participants_invite_prompt_server_acl_loading_error_text" = "You cannot invite this user at the moment, please try again later.";
+"introduce_federation_screen1_title" = "Federation";
+"introduce_federation_screen1_description" = "Secure communication across different organizations";
+"introduce_federation_screen2_title" = "Characterization";
+"introduce_federation_screen2_description" = "The symbol of overlaping circles helps to identify federated people.";
+"introduce_federation_screen3_title" = "Individual settings";
+"introduce_federation_screen3_description" = "Decide as an admin which room should be authorized for federation.";
+"introduce_federation_start" = "Understood";
diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift
index 260029cca..6a1631a90 100644
--- a/Riot/Generated/Images.swift
+++ b/Riot/Generated/Images.swift
@@ -55,6 +55,11 @@ internal class Asset: NSObject {
internal static let federationPillEnBumLight = ImageAsset(name: "federation_pill_en_bum_light")
internal static let fileAttachmentIcon = ImageAsset(name: "file_attachment_icon")
internal static let fileScanInfected = ImageAsset(name: "file_scan_infected")
+ internal static let introduceFederation1Dark = ImageAsset(name: "introduce_federation_1_dark")
+ internal static let introduceFederation1Light = ImageAsset(name: "introduce_federation_1_light")
+ internal static let introduceFederation2Dark = ImageAsset(name: "introduce_federation_2_dark")
+ internal static let introduceFederation2Light = ImageAsset(name: "introduce_federation_2_light")
+ internal static let introduceFederation3 = ImageAsset(name: "introduce_federation_3")
internal static let newFeatures = ImageAsset(name: "new_features")
internal static let qrcodeViewfinder = ImageAsset(name: "qrcode_viewfinder")
internal static let roomFederatedBumIconDark = ImageAsset(name: "room_federated_bum_icon_dark")
diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift
index cebaf0abb..1336e8ee9 100644
--- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift
+++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift
@@ -712,6 +712,15 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
private func bwiCheckForMatomoPromt() {
if BWIBuildSettings.shared.bwiMatomoEnabled && BWIAnalytics.sharedTracker.needsToShowPromt() {
self.allChatsViewController.bwiPresentMatomoConsentAlert()
+ } else {
+ // bwi: 5660 introduce federation
+ self.bwiShowFederationIntroduction()
+ }
+ }
+
+ private func bwiShowFederationIntroduction() {
+ if BWIBuildSettings.shared.showFederationIntroduction {
+ self.allChatsViewController.presentFederationIntroductionSheet()
}
}
diff --git a/Riot/Modules/Home/AllChats/AllChatsViewController.swift b/Riot/Modules/Home/AllChats/AllChatsViewController.swift
index b827f8e8e..2c0028ed0 100644
--- a/Riot/Modules/Home/AllChats/AllChatsViewController.swift
+++ b/Riot/Modules/Home/AllChats/AllChatsViewController.swift
@@ -17,6 +17,7 @@
// swiftlint:disable file_length
import UIKit
+import SwiftUI
import Reusable
protocol AllChatsViewControllerDelegate: AnyObject {
@@ -321,8 +322,27 @@ class AllChatsViewController: HomeViewController {
}
AppDelegate.theDelegate().checkAppVersion()
-
+ }
+
+ func presentFederationIntroductionSheet() {
+ guard BWIBuildSettings.shared.isFederationEnabled else {
+ return
+ }
+ guard self.mainSession.homeserverWellknown.shouldShowFederationIntroduction() else {
+ return
+ }
+
+ let notificationService = BWIAccountNotificationService(mxSession: self.mainSession)
+ guard notificationService.showFederationIntroductionFlag() else {
+ return
+ }
+
+ let viewController = UIHostingController(rootView: IntroduceFederationView().environmentObject(BWIThemeService.shared))
+ viewController.isModalInPresentation = true
+ present(viewController, animated: true) {
+ notificationService.setShowFederationIntroductionFlag(false)
+ }
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
@@ -477,6 +497,8 @@ class AllChatsViewController: HomeViewController {
style: .default,
handler: { action in
BWIAnalytics.sharedTracker.running = false
+ // bwi: 5660 introduce federation
+ self.presentFederationIntroductionSheet()
}))
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertOkButton,
@@ -484,6 +506,8 @@ class AllChatsViewController: HomeViewController {
handler: { action in
BWIAnalytics.sharedTracker.running = true
BWIAnalytics.sharedTracker.trackBwiValue(0, "General", "ConsentGiven", "popup")
+ // bwi: 5660 introduce federation
+ self.presentFederationIntroductionSheet()
}))
self.present(alert, animated: true)
diff --git a/bwi/DeveloperSettings/DeveloperSettingsView.swift b/bwi/DeveloperSettings/DeveloperSettingsView.swift
index 25a790b1e..b5932983b 100644
--- a/bwi/DeveloperSettings/DeveloperSettingsView.swift
+++ b/bwi/DeveloperSettings/DeveloperSettingsView.swift
@@ -23,7 +23,7 @@ import SwiftUI
@available(iOS 14.0, *)
class func makeViewController(session: MXSession) -> UIViewController {
- return UIHostingController(rootView: DeveloperSettingsView(session: session))
+ return UIHostingController(rootView: DeveloperSettingsView(session: session).environmentObject(BWIThemeService.shared))
}
}
@@ -32,16 +32,18 @@ import SwiftUI
struct DeveloperSettingsView: View {
let session: MXSession?
+ @EnvironmentObject var themeService: BWIThemeService
@State private var showAlert = false
@State private var showAlertBirthdayCampaign = false
@State private var permalinkPrefix: String? = UserDefaults.standard.string(forKey: "bwi_permalink_prefix")
+ @State private var showIntroduceFederation = false
var body: some View {
Form {
SwiftUI.Section {
Button(action: { showAlert = createNewPersonalNotesRoom(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperCreateNewPersonalNotesRoom)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
.alert(isPresented: $showAlert) {
@@ -50,7 +52,7 @@ struct DeveloperSettingsView: View {
Button(action: { showAlert = resetMatomoInfoScreen(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperResetMatomoInfo)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
.alert(isPresented: $showAlert) {
@@ -58,7 +60,7 @@ struct DeveloperSettingsView: View {
}
Button(action: { showAlertBirthdayCampaign = resetBirthdayCampaignScreen(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperSettingsResetBirthdayBanner)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
.alert(isPresented: $showAlertBirthdayCampaign) {
@@ -66,20 +68,39 @@ struct DeveloperSettingsView: View {
}
Button(action: { _ = restrictUser(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperRestrictUser)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
Button(action: { _ = unrestrictUser(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperUnrestrictUser)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
Button(action: { _ = unmarkBannerVersion(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperUnmarkBanner)
- .foregroundColor(Color(ThemeService.shared().theme.tintColor))
+ .foregroundColor(Color(themeService.theme.tintColor))
.font(.system(size: 17))
}
}
+ SwiftUI.Section(header: Text(BWIL10n.bwiSettingsDeveloperIntroduceFederation)) {
+ Button(action: { showIntroduceFederation = true }) {
+ Text(BWIL10n.bwiSettingsDeveloperIntroduceFederationPreview)
+ .foregroundColor(Color(themeService.theme.tintColor))
+ .font(.system(size: 17))
+ }
+ .sheet(isPresented: $showIntroduceFederation) {
+ IntroduceFederationView()
+ .interactiveDismissDisabled()
+ .environmentObject(BWIThemeService.shared)
+ }
+ if let session = session {
+ Button(action: { BWIAccountNotificationService(mxSession: session).setShowFederationIntroductionFlag(true) }) {
+ Text(BWIL10n.bwiSettingsDeveloperIntroduceFederationReset)
+ .foregroundColor(Color(themeService.theme.tintColor))
+ .font(.system(size: 17))
+ }
+ }
+ }
if BWIBuildSettings.shared.permalinkPrefixSettings && !BWIBuildSettings.shared.permalinkPrefixes.isEmpty {
SwiftUI.Section(header: Text(BWIL10n.settingsPermalinkPrefixPickerTitle)) {
Picker("", selection: $permalinkPrefix) {
@@ -129,12 +150,12 @@ struct DeveloperSettingsView: View {
}
-@available(iOS 14.0, *)
-struct DeveloperSettingsView_Previews: PreviewProvider {
- static var previews: some View {
- DeveloperSettingsView(session: nil)
- }
-}
+//@available(iOS 14.0, *)
+//struct DeveloperSettingsView_Previews: PreviewProvider {
+// static var previews: some View {
+// DeveloperSettingsView(session: nil)
+// }
+//}
// MARK: - Button Actions
@@ -153,7 +174,7 @@ fileprivate func resetMatomoInfoScreen(mxSession: MXSession?) -> Bool {
guard let mxSession = mxSession else {
return false
}
- BWIAnalyticsAccountDataService(mxSession: mxSession)
+ _ = BWIAnalyticsAccountDataService(mxSession: mxSession)
return true
}
diff --git a/bwi/IntroduceFederation/IntroduceFederationScreen1.swift b/bwi/IntroduceFederation/IntroduceFederationScreen1.swift
new file mode 100644
index 000000000..103bf36ff
--- /dev/null
+++ b/bwi/IntroduceFederation/IntroduceFederationScreen1.swift
@@ -0,0 +1,61 @@
+//
+/*
+ * Copyright (c) 2023 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
+
+struct IntroduceFederationScreen1: View {
+ @EnvironmentObject var themeService: BWIThemeService
+
+ var body: some View {
+ ZStack(alignment: .top) {
+ Color(themeService.theme.backgroundColor)
+
+ VStack(spacing: 26) {
+ ZStack {
+ Color(hex: 0xE3E8F0)
+ .frame(width: IntroduceFederationView.imageSize, height: IntroduceFederationView.imageSize)
+ .clipShape(Circle())
+ .padding(.leading, 50)
+ Image(uiImage: Asset.SharedImages.loginFlowLogo.image)
+ .resizable()
+ .aspectRatio(contentMode: .fill)
+ .clipShape(Circle())
+ .padding(1) // inner border size
+ .background(Color(hex: 0xE3E8F0))
+ .clipShape(Circle())
+ .padding(5) // outer border size
+ .background(Color(themeService.theme.backgroundColor))
+ .clipShape(Circle())
+ .frame(width: IntroduceFederationView.imageSize + 12, height: IntroduceFederationView.imageSize + 12)
+ .padding(.trailing, 50)
+ }
+ .padding(.bottom, 42)
+ Text(BWIL10n.introduceFederationScreen1Title)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 28, weight: .semibold))
+ .multilineTextAlignment(.center)
+ Text(BWIL10n.introduceFederationScreen1Description)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 17))
+ .multilineTextAlignment(.center)
+ Spacer()
+ }
+ .padding(.horizontal)
+ .padding(.top, IntroduceFederationView.topConstraintTitle - IntroduceFederationView.imageSize - 12)
+ }
+ }
+}
diff --git a/bwi/IntroduceFederation/IntroduceFederationScreen2.swift b/bwi/IntroduceFederation/IntroduceFederationScreen2.swift
new file mode 100644
index 000000000..1243d5f99
--- /dev/null
+++ b/bwi/IntroduceFederation/IntroduceFederationScreen2.swift
@@ -0,0 +1,51 @@
+//
+/*
+ * Copyright (c) 2023 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
+
+struct IntroduceFederationScreen2: View {
+ @EnvironmentObject var themeService: BWIThemeService
+
+ var body: some View {
+ ZStack(alignment: .top) {
+ Color(themeService.theme.backgroundColor)
+
+ VStack(spacing: 26) {
+ Image(uiImage: getImage(darkmode: themeService.isCurrentThemeDark))
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(height: IntroduceFederationView.imageSize + 12)
+ .padding(.bottom, 42)
+ Text(BWIL10n.introduceFederationScreen2Title)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 28, weight: .semibold))
+ .multilineTextAlignment(.center)
+ Text(BWIL10n.introduceFederationScreen2Description)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 17))
+ .multilineTextAlignment(.center)
+ Spacer()
+ }
+ .padding(.horizontal)
+ .padding(.top, IntroduceFederationView.topConstraintTitle - IntroduceFederationView.imageSize - 12)
+ }
+ }
+
+ private func getImage(darkmode: Bool) -> UIImage {
+ return darkmode ? Asset.Images.introduceFederation2Dark.image : Asset.Images.introduceFederation2Light.image
+ }
+}
diff --git a/bwi/IntroduceFederation/IntroduceFederationScreen3.swift b/bwi/IntroduceFederation/IntroduceFederationScreen3.swift
new file mode 100644
index 000000000..dbd20f05f
--- /dev/null
+++ b/bwi/IntroduceFederation/IntroduceFederationScreen3.swift
@@ -0,0 +1,52 @@
+//
+/*
+ * Copyright (c) 2023 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
+
+struct IntroduceFederationScreen3: View {
+ @EnvironmentObject var themeService: BWIThemeService
+ @Environment(\.dismiss) var dismiss
+
+ var body: some View {
+ VStack(spacing: 26) {
+ Image(uiImage: Asset.Images.introduceFederation3.image)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(height: IntroduceFederationView.topConstraintTitle)
+ .padding(.bottom, 42)
+ Text(BWIL10n.introduceFederationScreen3Title)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 28, weight: .semibold))
+ .multilineTextAlignment(.center)
+ Text(BWIL10n.introduceFederationScreen3Description)
+ .foregroundColor(Color(themeService.theme.textPrimaryColor))
+ .font(.system(size: 17))
+ .multilineTextAlignment(.center)
+ Spacer()
+ Button(action: onConfirm) {
+ Text(BWIL10n.introduceFederationStart)
+ }
+ .buttonStyle(PrimaryActionButtonStyle())
+ .padding(.bottom, 80)
+ }
+ .padding(.horizontal)
+ }
+
+ private func onConfirm() {
+ dismiss()
+ }
+}
diff --git a/bwi/IntroduceFederation/IntroduceFederationView.swift b/bwi/IntroduceFederation/IntroduceFederationView.swift
new file mode 100644
index 000000000..3e716006b
--- /dev/null
+++ b/bwi/IntroduceFederation/IntroduceFederationView.swift
@@ -0,0 +1,99 @@
+//
+/*
+ * Copyright (c) 2023 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
+
+enum VisibleScreen {
+ case screen1
+ case screen2
+ case screen3
+}
+
+struct IntroduceFederationView: View {
+ static let imageSize: CGFloat = 108
+ static let topConstraintTitle: CGFloat = 390
+ @EnvironmentObject var themeService: BWIThemeService
+ @State var visibleScreen = VisibleScreen.screen1
+
+ var body: some View {
+ TabView(selection: $visibleScreen) {
+ IntroduceFederationScreen1().tag(VisibleScreen.screen1).navigationBarHidden(true)
+ IntroduceFederationScreen2().tag(VisibleScreen.screen2).navigationBarHidden(true)
+ IntroduceFederationScreen3().tag(VisibleScreen.screen3).navigationBarHidden(true)
+ }
+ .tabViewStyle(.page(indexDisplayMode: .always))
+ .background {
+ Color(themeService.theme.backgroundColor)
+ .edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
+ }
+ .overlay(alignment: .bottom) {
+ HStack {
+ if visibleScreen != .screen1 {
+ Button(action: presentPreviousScreen) {
+ Image(systemName: "arrow.left")
+ .foregroundColor(Color(themeService.theme.textSecondaryColor))
+ .padding()
+ }
+ }
+ Spacer()
+ if visibleScreen != .screen3 {
+ Button(action: presentNextScreen) {
+ Image(systemName: "arrow.right")
+ .foregroundColor(Color(themeService.theme.textSecondaryColor))
+ .padding()
+ }
+ }
+ }
+ .padding()
+ }
+ .onAppear {
+ setupIndicatorColors()
+ }
+ }
+
+ private func setupIndicatorColors() {
+ UIPageControl.appearance().currentPageIndicatorTintColor = themeService.theme.textPrimaryColor
+ UIPageControl.appearance().pageIndicatorTintColor = themeService.theme.textSecondaryColor
+ }
+
+ private func presentNextScreen() {
+ withAnimation {
+ switch visibleScreen {
+ case .screen1:
+ visibleScreen = .screen2
+ case .screen2:
+ visibleScreen = .screen3
+ case .screen3:
+ break
+ }
+ }
+ }
+
+ private func presentPreviousScreen() {
+ withAnimation {
+ switch visibleScreen {
+ case .screen1:
+ break
+ case .screen2:
+ visibleScreen = .screen1
+ case .screen3:
+ visibleScreen = .screen2
+ }
+ }
+ }
+
+}
diff --git a/bwi/Tools/BWIAccountNotificationService.swift b/bwi/Tools/BWIAccountNotificationService.swift
index 57029b41c..f839a0bb0 100644
--- a/bwi/Tools/BWIAccountNotificationService.swift
+++ b/bwi/Tools/BWIAccountNotificationService.swift
@@ -24,13 +24,17 @@ import Foundation
enum CodingKeys: String, CodingKey {
case analyticsPromt = "should_show_analytics_consent_dialog"
case birthdayPromt = "should_show_ios_birthday_notification"
+ case federationAnnouncement = "should_show_federation_announcement"
+ case federationIntroduction = "should_show_federation_introduction"
}
let analyticsPromt: Bool
let birthdayPromt: Bool
+ let federationAnnouncement: Bool
+ let federationIntroduction: Bool
init(_ dict: [String: Any]) {
-
+
if let analyticsVal = dict[AccountNotifications.CodingKeys.analyticsPromt.rawValue] as? Bool {
analyticsPromt = analyticsVal
} else {
@@ -41,6 +45,16 @@ import Foundation
} else {
birthdayPromt = false
}
+ if let federationAnnouncementVal = dict[AccountNotifications.CodingKeys.federationAnnouncement.rawValue] as? Bool {
+ federationAnnouncement = federationAnnouncementVal
+ } else {
+ federationAnnouncement = false
+ }
+ if let federationIntroductionVal = dict[AccountNotifications.CodingKeys.federationIntroduction.rawValue] as? Bool {
+ federationIntroduction = federationIntroductionVal
+ } else {
+ federationIntroduction = false
+ }
}
}
@@ -70,4 +84,37 @@ import Foundation
session.setAccountData(notificationsDict, forType: AccountDataTypes.notifications, success: nil, failure: nil)
}
+
+ func showFederationAnnouncementFlag() -> Bool {
+ guard let notificationsDict = session.accountData.accountData(forEventType: AccountDataTypes.notifications) as? [String: Any] else {
+ return true
+ }
+
+ let notifications = AccountNotifications(notificationsDict)
+ return notifications.federationAnnouncement
+ }
+
+ func setShowFederationAnnouncementFlag(_ value: Bool) {
+ var notificationsDict = session.accountData.accountData(forEventType: AccountDataTypes.notifications) ?? [:]
+ notificationsDict[AccountNotifications.CodingKeys.federationAnnouncement.rawValue] = value
+
+ session.setAccountData(notificationsDict, forType: AccountDataTypes.notifications, success: nil, failure: nil)
+ }
+
+ func showFederationIntroductionFlag() -> Bool {
+ guard let notificationsDict = session.accountData.accountData(forEventType: AccountDataTypes.notifications) as? [String: Any] else {
+ return true
+ }
+
+ let notifications = AccountNotifications(notificationsDict)
+ return notifications.federationIntroduction
+ }
+
+ func setShowFederationIntroductionFlag(_ value: Bool) {
+ var notificationsDict = session.accountData.accountData(forEventType: AccountDataTypes.notifications) ?? [:]
+ notificationsDict[AccountNotifications.CodingKeys.federationIntroduction.rawValue] = value
+
+ session.setAccountData(notificationsDict, forType: AccountDataTypes.notifications, success: nil, failure: nil)
+ }
+
}
diff --git a/bwi/Tools/BWIThemeService.swift b/bwi/Tools/BWIThemeService.swift
new file mode 100644
index 000000000..f83199099
--- /dev/null
+++ b/bwi/Tools/BWIThemeService.swift
@@ -0,0 +1,48 @@
+//
+/*
+ * Copyright (c) 2022 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 Foundation
+import Combine
+
+class BWIThemeService: ObservableObject {
+ static let shared = BWIThemeService()
+ @Published var themeId: String?
+ @Published var theme: Theme
+ @Published var isCurrentThemeDark: Bool
+ var cancellable: Cancellable?
+
+ private init() {
+ let service = ThemeService.shared()
+ themeId = service.themeId
+ theme = service.theme
+ isCurrentThemeDark = service.isCurrentThemeDark()
+
+ cancellable = NotificationCenter.default
+ .publisher(for: .themeServiceDidChangeTheme)
+ .receive(on: DispatchQueue.main)
+ .sink() { _ in
+ self.themeDidChange()
+ }
+ }
+
+ private func themeDidChange() {
+ let service = ThemeService.shared()
+ themeId = service.themeId
+ theme = service.theme
+ isCurrentThemeDark = service.isCurrentThemeDark()
+ }
+}
diff --git a/bwi/Wellknown/Wellknown+Bwi.swift b/bwi/Wellknown/Wellknown+Bwi.swift
index ae290aada..4a6565701 100644
--- a/bwi/Wellknown/Wellknown+Bwi.swift
+++ b/bwi/Wellknown/Wellknown+Bwi.swift
@@ -66,6 +66,16 @@ public extension MXWellKnown {
}
}
+ // returns true if the federation introduction screen should be presented to the new users
+ @objc func shouldShowFederationIntroduction() -> Bool {
+ do {
+ let bwi = try WellknownBWI(dict: self.jsonDictionary()["de.bwi"] as! [String : Any])
+ return bwi.federation?.showIntroduction ?? false
+ } catch {
+ return false
+ }
+ }
+
// returns true if there is a valid url or no url, only the case "is url" but not valid is wrong
@objc func isValidDataPrivacyURL() -> Bool {
do {
diff --git a/bwi/Wellknown/WellknownBWI.swift b/bwi/Wellknown/WellknownBWI.swift
index 6b166a20a..3ff5e0898 100644
--- a/bwi/Wellknown/WellknownBWI.swift
+++ b/bwi/Wellknown/WellknownBWI.swift
@@ -17,20 +17,32 @@
import Foundation
-struct WellknownBWI {
+struct WellknownBWI: Decodable {
let dataPrivacyURL: String?
let imprintURL: String?
+ let federation: WellknownFederation?
init(dict: [String: Any]) throws {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
let decoder = JSONDecoder()
self = try decoder.decode(Self.self, from: jsonData)
}
-}
-
-extension WellknownBWI: Decodable {
+
enum CodingKeys: String, CodingKey {
case dataPrivacyURL = "data_privacy_url"
case imprintURL = "imprint_url"
+ case federation
+ }
+}
+
+struct WellknownFederation: Decodable {
+ let showAnnouncement: Bool?
+ let showIntroduction: Bool?
+ let enable: Bool?
+
+ enum CodingKeys: String, CodingKey {
+ case showAnnouncement = "show_announcement"
+ case showIntroduction = "show_introduction"
+ case enable
}
}