From 682f91a2ff6c7d8c3b335d245f4419c59b7dc18f Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Wed, 16 Apr 2025 16:36:19 +0100 Subject: [PATCH] Add the new bloom style under a feature flag. (#4033) * Refactor the bloom into a modifier. It currently depends on the home screen context but that will be removed in the future. * Add an initial implementation of the new bloom using an image on the navigation item's appearance. * Add a feature flag to control the new bloom. --- ElementX.xcodeproj/project.pbxproj | 8 +- .../Sources/Application/AppSettings.swift | 4 + .../Screens/HomeScreen/HomeScreenModels.swift | 4 + .../HomeScreen/HomeScreenViewModel.swift | 2 +- .../HomeScreen/View/BloomModifier.swift | 211 ++++++++++++++++++ .../Screens/HomeScreen/View/BloomView.swift | 34 --- .../Screens/HomeScreen/View/HomeScreen.swift | 108 +-------- .../DeveloperOptionsScreenModels.swift | 1 + .../View/DeveloperOptionsScreen.swift | 5 + 9 files changed, 234 insertions(+), 143 deletions(-) create mode 100644 ElementX/Sources/Screens/HomeScreen/View/BloomModifier.swift delete mode 100644 ElementX/Sources/Screens/HomeScreen/View/BloomView.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 7acf089ab..84eb3efab 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -484,7 +484,6 @@ 5DFC2A889D3B39DD47AC63A8 /* PillUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C537DE821FED94D23467B6C4 /* PillUtilities.swift */; }; 5EC046E41755C095DAB1C3FF /* TimelineProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8C9BBB729C941BEE0E2A63 /* TimelineProviderProtocol.swift */; }; 5EDBDE802761B5ECB54E6787 /* LogLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2711E5996016ABD6EAAEB58A /* LogLevel.swift */; }; - 5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BEB970F500BFB248443FA1 /* BloomView.swift */; }; 5F06AD3C66884CE793AE6119 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; }; 5F0B5797D1BFF2A51084B4C3 /* PinnedEventsTimelineScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86D7CD5CA270BFC3EBB450CA /* PinnedEventsTimelineScreenViewModel.swift */; }; 5F35069E13D71DD88633A4B2 /* preview_video.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 45A4B934BA41D6C255900265 /* preview_video.jpg */; }; @@ -959,6 +958,7 @@ BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A3B7637DDBD6AA97AC2545 /* CameraPicker.swift */; }; BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */; }; BB9B800C6094E34860E89DC5 /* AppLockSetupBiometricsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */; }; + BC1222EDFF0C240F14259315 /* BloomModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D152423EE6CF0ECCC84091A /* BloomModifier.swift */; }; BC7CA1379D7C24F47B1B8B7E /* PaginationIndicatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E7F7A975514E850A834B29F /* PaginationIndicatorRoomTimelineView.swift */; }; BCC864190651B3A3CF51E4DF /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; }; BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */; }; @@ -2044,6 +2044,7 @@ 8C44BBC892499BE45B074F89 /* AppLockScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenCoordinator.swift; sourceTree = ""; }; 8C8616254EE40CA8BA5E9BC2 /* VideoRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItemContent.swift; sourceTree = ""; }; 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonStyle.swift; sourceTree = ""; }; + 8D152423EE6CF0ECCC84091A /* BloomModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloomModifier.swift; sourceTree = ""; }; 8D1FA20DAB853C1156054912 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/InfoPlist.strings; sourceTree = ""; }; 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; @@ -2415,7 +2416,6 @@ D79BB714D28C9F588DD69353 /* SecureBackupScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModelProtocol.swift; sourceTree = ""; }; D7B18089ED50324583BB2FB7 /* EditRoomAddressScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModelProtocol.swift; sourceTree = ""; }; D7BB243B26D54EF1A0C422C0 /* NotificationContentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentBuilder.swift; sourceTree = ""; }; - D7BEB970F500BFB248443FA1 /* BloomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloomView.swift; sourceTree = ""; }; D80807B554CF9C524F98674F /* ManageRoomMemberSheetViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageRoomMemberSheetViewModelTests.swift; sourceTree = ""; }; D879DC5515B1D42577F96C94 /* RoomSelectionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreen.swift; sourceTree = ""; }; D8AA084E10B80D64449C02A9 /* SessionVerificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationTests.swift; sourceTree = ""; }; @@ -3858,7 +3858,7 @@ 4F43EBE458FBE634996AD7C6 /* View */ = { isa = PBXGroup; children = ( - D7BEB970F500BFB248443FA1 /* BloomView.swift */, + 8D152423EE6CF0ECCC84091A /* BloomModifier.swift */, B902EA6CD3296B0E10EE432B /* HomeScreen.swift */, A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */, C0FEA560929DD73FFEF8C3DF /* HomeScreenEmptyStateView.swift */, @@ -7029,7 +7029,7 @@ 8C91D242BEEC657FABCC0B95 /* BlockedUsersScreenModels.swift in Sources */, 934051B17A884AB0635DF81B /* BlockedUsersScreenViewModel.swift in Sources */, A4B123C635F70DDD4BC2FAC9 /* BlockedUsersScreenViewModelProtocol.swift in Sources */, - 5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */, + BC1222EDFF0C240F14259315 /* BloomModifier.swift in Sources */, 54FDA3625AACBD9E438D084D /* BlurEffectView.swift in Sources */, B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */, E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */, diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 78046aa92..28c5dc4c0 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -48,6 +48,7 @@ final class AppSettings { case hideUnreadMessagesBadge case hideInviteAvatars case timelineMediaVisibility + case isNewBloomEnabled case elementCallBaseURLOverride @@ -361,6 +362,9 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.timelineMediaVisibility, defaultValue: TimelineMediaVisibility.always, storageType: .userDefaults(store)) var timelineMediaVisibility + + @UserPreference(key: UserDefaultsKeys.isNewBloomEnabled, defaultValue: false, storageType: .userDefaults(store)) + var isNewBloomEnabled } extension AppSettings: CommonSettingsProtocol { } diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index 114f7fb71..9de901244 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -105,6 +105,10 @@ struct HomeScreenViewState: BindableState { var reportRoomEnabled = false + // Intentionally not mutable so that we don't have to reset the navigation bar's + // appearance whenever the feature flag is toggled (requires a restart). + let isNewBloomEnabled: Bool + var visibleRooms: [HomeScreenRoom] { if roomListMode == .skeletons { return placeholderRooms diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 390cc7b63..0251fc95f 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -37,7 +37,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol roomSummaryProvider = userSession.clientProxy.roomSummaryProvider - super.init(initialViewState: .init(userID: userSession.clientProxy.userID), + super.init(initialViewState: .init(userID: userSession.clientProxy.userID, isNewBloomEnabled: appSettings.isNewBloomEnabled), mediaProvider: userSession.mediaProvider) userSession.clientProxy.userAvatarURLPublisher diff --git a/ElementX/Sources/Screens/HomeScreen/View/BloomModifier.swift b/ElementX/Sources/Screens/HomeScreen/View/BloomModifier.swift new file mode 100644 index 000000000..d1c36e46e --- /dev/null +++ b/ElementX/Sources/Screens/HomeScreen/View/BloomModifier.swift @@ -0,0 +1,211 @@ +// +// Copyright 2023, 2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import Compound +import SwiftUI +import SwiftUIIntrospect + +extension View { + // Note: The dependency on HomeScreenViewModel.Context will be removed in the next iteration. + @ViewBuilder + func bloom(context: HomeScreenViewModel.Context, scrollViewAdapter: ScrollViewAdapter, isNewBloomEnabled: Bool) -> some View { + if isNewBloomEnabled { + modifier(NewBloomModifier()) + } else { + modifier(BloomModifier(context: context, scrollViewAdapter: scrollViewAdapter)) + } + } +} + +struct NewBloomModifier: ViewModifier { + @State private var standardAppearance = UINavigationBarAppearance() + @State private var scrollEdgeAppearance = UINavigationBarAppearance() + + @State private var bloomGradientImage: UIImage? + + func body(content: Content) -> some View { + content + .introspect(.viewController, on: .supportedVersions, customize: configureBloom) + } + + private func configureBloom(controller: UIViewController) { + guard controller.navigationItem.standardAppearance != standardAppearance, + controller.navigationItem.scrollEdgeAppearance != scrollEdgeAppearance else { + return + } + + let image = makeBloomImage() + + standardAppearance.configureWithDefaultBackground() + standardAppearance.backgroundImage = image + standardAppearance.backgroundImageContentMode = .scaleToFill + controller.navigationItem.standardAppearance = standardAppearance + + scrollEdgeAppearance.configureWithTransparentBackground() + scrollEdgeAppearance.backgroundImage = image + scrollEdgeAppearance.backgroundImageContentMode = .scaleToFill + scrollEdgeAppearance.backgroundColor = .compound.bgCanvasDefault + controller.navigationItem.scrollEdgeAppearance = scrollEdgeAppearance + } + + private func makeBloomImage() -> UIImage? { + if let bloomGradientImage { + return bloomGradientImage + } + + let newImage = ImageRenderer(content: bloomGradient).uiImage + Task { bloomGradientImage = newImage } + return newImage + } + + private var bloomGradient: some View { + LinearGradient(colors: [.compound._bgOwnPill, .clear], // This isn't the final gradient. + startPoint: .top, + endPoint: .bottom) + .ignoresSafeArea(edges: .all) + .frame(width: 100, height: 100) + } +} + +struct BloomModifier: ViewModifier { + @ObservedObject var context: HomeScreenViewModel.Context + + let scrollViewAdapter: ScrollViewAdapter + + // Bloom components + @State private var bloomView: UIView? + @State private var leftBarButtonView: UIView? + @State private var gradientView: UIView? + @State private var navigationBarContainer: UIView? + @State private var hairlineView: UIView? + + func body(content: Content) -> some View { + content + .introspect(.viewController, on: .supportedVersions) { controller in + Task { + if bloomView == nil { + makeBloomView(controller: controller) + } + } + let isTopController = controller.navigationController?.topViewController != controller + let isHidden = isTopController || context.isSearchFieldFocused + if let bloomView { + bloomView.isHidden = isHidden + UIView.transition(with: bloomView, duration: 1.75, options: .curveEaseInOut) { + bloomView.alpha = isTopController ? 0 : 1 + } + } + gradientView?.isHidden = isHidden + navigationBarContainer?.clipsToBounds = !isHidden + hairlineView?.isHidden = isHidden || !scrollViewAdapter.isAtTopEdge.value + if !isHidden { + updateBloomCenter() + } + } + .onReceive(scrollViewAdapter.isAtTopEdge.removeDuplicates()) { value in + hairlineView?.isHidden = !value + guard let gradientView else { + return + } + if value { + UIView.transition(with: gradientView, duration: 0.3, options: .curveEaseIn) { + gradientView.alpha = 0 + } + } else { + gradientView.alpha = 1 + } + } + } + + private var bloomGradient: some View { + LinearGradient(colors: [.clear, .compound.bgCanvasDefault], startPoint: .top, endPoint: .bottom) + .mask { + LinearGradient(stops: [.init(color: .white, location: 0.75), .init(color: .clear, location: 1.0)], + startPoint: .leading, + endPoint: .trailing) + } + .ignoresSafeArea(edges: .all) + } + + private func makeBloomView(controller: UIViewController) { + guard let navigationBarContainer = controller.navigationController?.navigationBar.subviews.first, + let leftBarButtonView = controller.navigationItem.leadingItemGroups.first?.barButtonItems.first?.customView else { + return + } + + let bloomController = UIHostingController(rootView: bloom) + bloomController.view.translatesAutoresizingMaskIntoConstraints = true + bloomController.view.backgroundColor = .clear + navigationBarContainer.insertSubview(bloomController.view, at: 0) + self.leftBarButtonView = leftBarButtonView + bloomView = bloomController.view + self.navigationBarContainer = navigationBarContainer + updateBloomCenter() + + let gradientController = UIHostingController(rootView: bloomGradient) + gradientController.view.backgroundColor = .clear + gradientController.view.translatesAutoresizingMaskIntoConstraints = false + navigationBarContainer.insertSubview(gradientController.view, aboveSubview: bloomController.view) + + let constraints = [gradientController.view.bottomAnchor.constraint(equalTo: navigationBarContainer.bottomAnchor), + gradientController.view.trailingAnchor.constraint(equalTo: navigationBarContainer.trailingAnchor), + gradientController.view.leadingAnchor.constraint(equalTo: navigationBarContainer.leadingAnchor), + gradientController.view.heightAnchor.constraint(equalToConstant: 40)] + constraints.forEach { $0.isActive = true } + gradientView = gradientController.view + + let dividerController = UIHostingController(rootView: Divider().ignoresSafeArea()) + dividerController.view.translatesAutoresizingMaskIntoConstraints = false + navigationBarContainer.addSubview(dividerController.view) + let dividerConstraints = [dividerController.view.bottomAnchor.constraint(equalTo: gradientController.view.bottomAnchor), + dividerController.view.widthAnchor.constraint(equalTo: gradientController.view.widthAnchor), + dividerController.view.leadingAnchor.constraint(equalTo: gradientController.view.leadingAnchor)] + dividerConstraints.forEach { $0.isActive = true } + hairlineView = dividerController.view + } + + private func updateBloomCenter() { + guard let leftBarButtonView, + let bloomView, + let navigationBarContainer = bloomView.superview else { + return + } + + let center = leftBarButtonView.convert(leftBarButtonView.center, to: navigationBarContainer.coordinateSpace) + bloomView.center = center + } + + private var bloom: some View { + BloomView(context: context) + } +} + +private struct BloomView: View { + @ObservedObject var context: HomeScreenViewModel.Context + @Environment(\.colorScheme) private var colorScheme + + var body: some View { + ZStack { + avatar + .blur(radius: 64) + .blendMode(colorScheme == .dark ? .exclusion : .hardLight) + .opacity(colorScheme == .dark ? 0.50 : 0.20) + avatar + .blur(radius: 64) + .blendMode(.color) + .opacity(colorScheme == .dark ? 0.20 : 0.80) + } + } + + private var avatar: some View { + LoadableAvatarImage(url: context.viewState.userAvatarURL, + name: context.viewState.userDisplayName, + contentID: context.viewState.userID, + avatarSize: .custom(256), + mediaProvider: context.mediaProvider) + } +} diff --git a/ElementX/Sources/Screens/HomeScreen/View/BloomView.swift b/ElementX/Sources/Screens/HomeScreen/View/BloomView.swift deleted file mode 100644 index b7123552b..000000000 --- a/ElementX/Sources/Screens/HomeScreen/View/BloomView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright 2023, 2024 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import SwiftUI - -struct BloomView: View { - @ObservedObject var context: HomeScreenViewModel.Context - @Environment(\.colorScheme) private var colorScheme - - var body: some View { - ZStack { - avatar - .blur(radius: 64) - .blendMode(colorScheme == .dark ? .exclusion : .hardLight) - .opacity(colorScheme == .dark ? 0.50 : 0.20) - avatar - .blur(radius: 64) - .blendMode(.color) - .opacity(colorScheme == .dark ? 0.20 : 0.80) - } - } - - private var avatar: some View { - LoadableAvatarImage(url: context.viewState.userAvatarURL, - name: context.viewState.userDisplayName, - contentID: context.viewState.userID, - avatarSize: .custom(256), - mediaProvider: context.mediaProvider) - } -} diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift index 68f6a76f5..1d991297e 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift @@ -7,21 +7,14 @@ import Combine import Compound +import SentrySwiftUI import SwiftUI -import SwiftUIIntrospect struct HomeScreen: View { @ObservedObject var context: HomeScreenViewModel.Context @State private var scrollViewAdapter = ScrollViewAdapter() - // Bloom components - @State private var bloomView: UIView? - @State private var leftBarButtonView: UIView? - @State private var gradientView: UIView? - @State private var navigationBarContainer: UIView? - @State private var hairlineView: UIView? - var body: some View { HomeScreenContent(context: context, scrollViewAdapter: scrollViewAdapter) .alert(item: $context.alertInfo) @@ -32,102 +25,13 @@ struct HomeScreen: View { .toolbar { toolbar } .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) .track(screen: .Home) - .introspect(.viewController, on: .supportedVersions) { controller in - Task { - if bloomView == nil { - makeBloomView(controller: controller) - } - } - let isTopController = controller.navigationController?.topViewController != controller - let isHidden = isTopController || context.isSearchFieldFocused - if let bloomView { - bloomView.isHidden = isHidden - UIView.transition(with: bloomView, duration: 1.75, options: .curveEaseInOut) { - bloomView.alpha = isTopController ? 0 : 1 - } - } - gradientView?.isHidden = isHidden - navigationBarContainer?.clipsToBounds = !isHidden - hairlineView?.isHidden = isHidden || !scrollViewAdapter.isAtTopEdge.value - if !isHidden { - updateBloomCenter() - } - } - .onReceive(scrollViewAdapter.isAtTopEdge.removeDuplicates()) { value in - hairlineView?.isHidden = !value - guard let gradientView else { - return - } - if value { - UIView.transition(with: gradientView, duration: 0.3, options: .curveEaseIn) { - gradientView.alpha = 0 - } - } else { - gradientView.alpha = 1 - } - } + .bloom(context: context, + scrollViewAdapter: scrollViewAdapter, + isNewBloomEnabled: context.viewState.isNewBloomEnabled) .sentryTrace("\(Self.self)") } // MARK: - Private - - private var bloomGradient: some View { - LinearGradient(colors: [.clear, .compound.bgCanvasDefault], startPoint: .top, endPoint: .bottom) - .mask { - LinearGradient(stops: [.init(color: .white, location: 0.75), .init(color: .clear, location: 1.0)], - startPoint: .leading, - endPoint: .trailing) - } - .ignoresSafeArea(edges: .all) - } - - private func makeBloomView(controller: UIViewController) { - guard let navigationBarContainer = controller.navigationController?.navigationBar.subviews.first, - let leftBarButtonView = controller.navigationItem.leadingItemGroups.first?.barButtonItems.first?.customView else { - return - } - - let bloomController = UIHostingController(rootView: bloom) - bloomController.view.translatesAutoresizingMaskIntoConstraints = true - bloomController.view.backgroundColor = .clear - navigationBarContainer.insertSubview(bloomController.view, at: 0) - self.leftBarButtonView = leftBarButtonView - bloomView = bloomController.view - self.navigationBarContainer = navigationBarContainer - updateBloomCenter() - - let gradientController = UIHostingController(rootView: bloomGradient) - gradientController.view.backgroundColor = .clear - gradientController.view.translatesAutoresizingMaskIntoConstraints = false - navigationBarContainer.insertSubview(gradientController.view, aboveSubview: bloomController.view) - - let constraints = [gradientController.view.bottomAnchor.constraint(equalTo: navigationBarContainer.bottomAnchor), - gradientController.view.trailingAnchor.constraint(equalTo: navigationBarContainer.trailingAnchor), - gradientController.view.leadingAnchor.constraint(equalTo: navigationBarContainer.leadingAnchor), - gradientController.view.heightAnchor.constraint(equalToConstant: 40)] - constraints.forEach { $0.isActive = true } - gradientView = gradientController.view - - let dividerController = UIHostingController(rootView: Divider().ignoresSafeArea()) - dividerController.view.translatesAutoresizingMaskIntoConstraints = false - navigationBarContainer.addSubview(dividerController.view) - let dividerConstraints = [dividerController.view.bottomAnchor.constraint(equalTo: gradientController.view.bottomAnchor), - dividerController.view.widthAnchor.constraint(equalTo: gradientController.view.widthAnchor), - dividerController.view.leadingAnchor.constraint(equalTo: gradientController.view.leadingAnchor)] - dividerConstraints.forEach { $0.isActive = true } - hairlineView = dividerController.view - } - - private func updateBloomCenter() { - guard let leftBarButtonView, - let bloomView, - let navigationBarContainer = bloomView.superview else { - return - } - - let center = leftBarButtonView.convert(leftBarButtonView.center, to: navigationBarContainer.coordinateSpace) - bloomView.center = center - } @ToolbarContentBuilder private var toolbar: some ToolbarContent { @@ -152,10 +56,6 @@ struct HomeScreen: View { } } - private var bloom: some View { - BloomView(context: context) - } - @ViewBuilder private var newRoomButton: some View { switch context.viewState.roomListMode { diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index 82b7ca1d8..ea89e82b8 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -47,6 +47,7 @@ protocol DeveloperOptionsProtocol: AnyObject { var reportRoomEnabled: Bool { get set } var reportInviteEnabled: Bool { get set } var threadsEnabled: Bool { get set } + var isNewBloomEnabled: Bool { get set } } extension AppSettings: DeveloperOptionsProtocol { } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 99610f988..ab92a2fd1 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -49,6 +49,11 @@ struct DeveloperOptionsScreen: View { Toggle(isOn: $context.fuzzyRoomListSearchEnabled) { Text("Fuzzy searching") } + + Toggle(isOn: $context.isNewBloomEnabled) { + Text("New bloom appearance") + Text("Requires app reboot") + } } Section("Join rules") {