diff --git a/WireUI/Sources/WireMainNavigationUI/Containers/MainTabBarController.swift b/WireUI/Sources/WireMainNavigationUI/Containers/MainTabBarController.swift index 56bbda4e4d2..5b31e155dc4 100644 --- a/WireUI/Sources/WireMainNavigationUI/Containers/MainTabBarController.swift +++ b/WireUI/Sources/WireMainNavigationUI/Containers/MainTabBarController.swift @@ -68,6 +68,7 @@ public final class MainTabBarController< private weak var conversationListNavigationController: UINavigationController! private weak var archiveNavigationController: UINavigationController! + private weak var meetingsNavigationController: UINavigationController! private weak var settingsNavigationController: UINavigationController! private weak var _conversationListUI: ConversationListUI? @@ -75,10 +76,14 @@ public final class MainTabBarController< private weak var _settingsUI: SettingsUI? private weak var _conversationUI: ConversationUI? private weak var _settingsContentUI: UIViewController? + /// We should use DeveloperFlag 'wireMeetings' after moving it to WireFoundation: + /// https://wearezeta.atlassian.net/browse/WPB-19065 + private var showMeetings: Bool // MARK: - Life Cycle - public required init() { + public init(showMeetings: Bool) { + self.showMeetings = showMeetings super.init(nibName: nil, bundle: nil) setupTabs() setupAppearance() @@ -98,16 +103,25 @@ public final class MainTabBarController< archiveNavigationController.navigationBar.isTranslucent = false self.archiveNavigationController = archiveNavigationController + let meetingsNavigationController = UINavigationController() + meetingsNavigationController.navigationBar.isTranslucent = false + self.meetingsNavigationController = meetingsNavigationController + let settingsNavigationController = UINavigationController() settingsNavigationController.navigationBar.isTranslucent = false self.settingsNavigationController = settingsNavigationController - viewControllers = [ + var tabs: [UIViewController] = [ conversationListNavigationController, archiveNavigationController, settingsNavigationController ] + if showMeetings { + tabs.insert(meetingsNavigationController, at: 2) + } + setViewControllers(tabs, animated: false) + for content in MainTabBarControllerContent.allCases { switch content { case .conversations: @@ -148,6 +162,25 @@ public final class MainTabBarController< ) archiveNavigationController.tabBarItem = tabBarItem + case .meetings: + let tabBarItem = UITabBarItem( + title: String(localized: "tabBar.meetings.title", bundle: .module), + image: .init(resource: .videoCall), + selectedImage: .init(resource: .videoCallFilled) + ) + tabBarItem.accessibilityIdentifier = "bottomBarMeetingsButton" + tabBarItem.accessibilityLabel = String( + localized: "tabBar.meetings.description", + table: "Accessibility", + bundle: .module + ) + tabBarItem.accessibilityHint = String( + localized: "tabBar.meetings.hint", + table: "Accessibility", + bundle: .module + ) + meetingsNavigationController.tabBarItem = tabBarItem + case .settings: let tabBarItem = UITabBarItem( title: String(localized: "tabBar.settings.title", bundle: .module), diff --git a/WireUI/Sources/WireMainNavigationUI/Coordinator/AnyMainCoordinator.swift b/WireUI/Sources/WireMainNavigationUI/Coordinator/AnyMainCoordinator.swift index d877e93b2bd..25f88ef9718 100644 --- a/WireUI/Sources/WireMainNavigationUI/Coordinator/AnyMainCoordinator.swift +++ b/WireUI/Sources/WireMainNavigationUI/Coordinator/AnyMainCoordinator.swift @@ -27,6 +27,7 @@ public final class AnyMainCoordinator Void private let _showArchive: @MainActor () async -> Void private let _showSettings: @MainActor () async -> Void + private let _showMeetings: @MainActor () async -> Void private let _showConversation: @MainActor ( _ conversation: ConversationModel, _ message: ConversationMessageModel? @@ -54,6 +55,9 @@ public final class AnyMainCoordinator: NSObject, MainCoordinatorProto showSettingsContent(.init(.account)) // TODO: [WPB-11347] make the selection visible } + public func showMeetings() async { + // TODO: [WPB-20272]: add list of meetings + } + public func showConversation( conversation: ConversationModel, message: ConversationMessageModel? @@ -409,6 +413,9 @@ public final class MainCoordinator: NSObject, MainCoordinatorProto case .archive: sidebar.selectedMenuItem = .init(.archive) + case .meetings: + sidebar.selectedMenuItem = .init(.meetings) + case .settings: sidebar.selectedMenuItem = .init(.settings) } diff --git a/WireUI/Sources/WireMainNavigationUI/Models/MainSidebarMenuItem.swift b/WireUI/Sources/WireMainNavigationUI/Models/MainSidebarMenuItem.swift index 389e6f668ad..65f86382eb1 100644 --- a/WireUI/Sources/WireMainNavigationUI/Models/MainSidebarMenuItem.swift +++ b/WireUI/Sources/WireMainNavigationUI/Models/MainSidebarMenuItem.swift @@ -31,6 +31,7 @@ public enum MainSidebarMenuItem: Sendable, Equatable { case drafts case archive case folders + case meetings // bottom case settings } diff --git a/WireUI/Sources/WireMainNavigationUI/Models/MainTabBarControllerContent.swift b/WireUI/Sources/WireMainNavigationUI/Models/MainTabBarControllerContent.swift index 565e1bdcb2e..1e8cc2e2550 100644 --- a/WireUI/Sources/WireMainNavigationUI/Models/MainTabBarControllerContent.swift +++ b/WireUI/Sources/WireMainNavigationUI/Models/MainTabBarControllerContent.swift @@ -22,4 +22,5 @@ public enum MainTabBarControllerContent: Int, CaseIterable { case conversations case archive case settings + case meetings } diff --git a/WireUI/Sources/WireMainNavigationUI/Preview/MainSplitViewControllerPreview.swift b/WireUI/Sources/WireMainNavigationUI/Preview/MainSplitViewControllerPreview.swift index 77111e2f316..32ca5e72280 100644 --- a/WireUI/Sources/WireMainNavigationUI/Preview/MainSplitViewControllerPreview.swift +++ b/WireUI/Sources/WireMainNavigationUI/Preview/MainSplitViewControllerPreview.swift @@ -23,7 +23,7 @@ func MainSplitViewControllerPreview() -> UISplitViewController { let splitViewController = MainSplitViewController( sidebar: PreviewSidebarViewController("sidebar"), noConversationPlaceholder: UIHostingController(rootView: Text(verbatim: "no conversation placeholder")), - tabController: .init() + tabController: .init(showMeetings: false) ) splitViewController.conversationListUI = PreviewConversationListViewController("conversation list") return splitViewController diff --git a/WireUI/Sources/WireMainNavigationUI/Preview/MainTabBarControllerPreview.swift b/WireUI/Sources/WireMainNavigationUI/Preview/MainTabBarControllerPreview.swift index d23534f2dd2..941a66c46b0 100644 --- a/WireUI/Sources/WireMainNavigationUI/Preview/MainTabBarControllerPreview.swift +++ b/WireUI/Sources/WireMainNavigationUI/Preview/MainTabBarControllerPreview.swift @@ -20,7 +20,7 @@ import SwiftUI @MainActor func MainTabBarControllerPreview() -> some MainTabBarControllerProtocol { - let tabBarController = PreviewTabBarController() + let tabBarController = PreviewTabBarController(showMeetings: false) tabBarController.conversationListUI = .init("conversationList") tabBarController.archiveUI = PlaceholderViewController() tabBarController.settingsUI = .init() diff --git a/WireUI/Sources/WireMainNavigationUI/Protocols/Coordinator/MainCoordinatorProtocol.swift b/WireUI/Sources/WireMainNavigationUI/Protocols/Coordinator/MainCoordinatorProtocol.swift index b7e33b496dd..87214c80049 100644 --- a/WireUI/Sources/WireMainNavigationUI/Protocols/Coordinator/MainCoordinatorProtocol.swift +++ b/WireUI/Sources/WireMainNavigationUI/Protocols/Coordinator/MainCoordinatorProtocol.swift @@ -35,6 +35,8 @@ public protocol MainCoordinatorProtocol: AnyObject { func showArchive() async @MainActor func showSettings() async + @MainActor + func showMeetings() async @MainActor func showConversation(conversation: ConversationModel, message: ConversationMessageModel?) async diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/Contents.json b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/Contents.json b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/Contents.json new file mode 100644 index 00000000000..e388c79f4e0 --- /dev/null +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "VideoCall.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/VideoCall.svg b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/VideoCall.svg new file mode 100644 index 00000000000..08d70c6877f --- /dev/null +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCall.imageset/VideoCall.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/Contents.json b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/Contents.json new file mode 100644 index 00000000000..af3b035e2fe --- /dev/null +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "VideoCallFilled.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/VideoCallFilled.svg b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/VideoCallFilled.svg new file mode 100644 index 00000000000..ce8f6a70196 --- /dev/null +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Images.xcassets/VideoCallFilled.imageset/VideoCallFilled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Accessibility.xcstrings b/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Accessibility.xcstrings index f2b02e5e6f9..ec659dae2e1 100644 --- a/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Accessibility.xcstrings +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Accessibility.xcstrings @@ -497,6 +497,28 @@ } } }, + "tabBar.meetings.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meetings" + } + } + } + }, + "tabBar.meetings.hint" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "List of meetings" + } + } + } + }, "tabBar.settings.description" : { "localizations" : { "ar" : { @@ -747,4 +769,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Localizable.xcstrings b/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Localizable.xcstrings index b01fa011906..cd8aaa4685f 100644 --- a/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Localizable.xcstrings +++ b/WireUI/Sources/WireMainNavigationUI/Resources/Localization/Localizable.xcstrings @@ -249,6 +249,17 @@ } } }, + "tabBar.meetings.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meetings" + } + } + } + }, "tabBar.settings.title" : { "localizations" : { "ar" : { @@ -375,4 +386,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/WireUI/Sources/WireSidebarUI/Models/SidebarModel.swift b/WireUI/Sources/WireSidebarUI/Models/SidebarModel.swift index a6c02be1059..dd6b38a673a 100644 --- a/WireUI/Sources/WireSidebarUI/Models/SidebarModel.swift +++ b/WireUI/Sources/WireSidebarUI/Models/SidebarModel.swift @@ -41,6 +41,7 @@ final class SidebarModel: ObservableObject { } @Published var showUnreadFilters: Bool = false + @Published var showMeetings: Bool = false let accountImageAction: () -> Void let menuItemAction: (_ selectedMenuItem: SidebarSelectableMenuItem) -> Void diff --git a/WireUI/Sources/WireSidebarUI/Models/SidebarSelectableMenuItem.swift b/WireUI/Sources/WireSidebarUI/Models/SidebarSelectableMenuItem.swift index 2884e9bf1c4..e43f7d7003d 100644 --- a/WireUI/Sources/WireSidebarUI/Models/SidebarSelectableMenuItem.swift +++ b/WireUI/Sources/WireSidebarUI/Models/SidebarSelectableMenuItem.swift @@ -30,6 +30,7 @@ public enum SidebarSelectableMenuItem: Comparable, Sendable, Hashable { case replies case drafts case folders + case meetings // archived conversations case archive // bottom diff --git a/WireUI/Sources/WireSidebarUI/Resources/Localization/en.lproj/Localizable.strings b/WireUI/Sources/WireSidebarUI/Resources/Localization/en.lproj/Localizable.strings index 21cbacf06a9..9f83e2797b9 100644 --- a/WireUI/Sources/WireSidebarUI/Resources/Localization/en.lproj/Localizable.strings +++ b/WireUI/Sources/WireSidebarUI/Resources/Localization/en.lproj/Localizable.strings @@ -31,6 +31,9 @@ "sidebar.conversation_filter.folders.title" = "Folders"; "sidebar.conversation_filter.archived.title" = "Archive"; +"sidebar.meetings.title" = "Meetings"; +"sidebar.meetings.all_meetings.title" = "All Meetings"; + "sidebar.contacts.title" = "Contacts"; "sidebar.contacts.connect.title" = "Connect"; diff --git a/WireUI/Sources/WireSidebarUI/Views/Preview/SidebarPreview.swift b/WireUI/Sources/WireSidebarUI/Views/Preview/SidebarPreview.swift index d7994130ace..ca874723cd4 100644 --- a/WireUI/Sources/WireSidebarUI/Views/Preview/SidebarPreview.swift +++ b/WireUI/Sources/WireSidebarUI/Views/Preview/SidebarPreview.swift @@ -49,6 +49,7 @@ struct SidebarPreview: View { accountInfo: accountInfo, selectedMenuItem: $selectedMenuItem, showUnreadFilters: false, + showMeetings: false, accountImageAction: {}, foldersAction: { _ in }, supportAction: {}, diff --git a/WireUI/Sources/WireSidebarUI/Views/SidebarView.swift b/WireUI/Sources/WireSidebarUI/Views/SidebarView.swift index bb1b48b1c93..0c5ba53e34f 100644 --- a/WireUI/Sources/WireSidebarUI/Views/SidebarView.swift +++ b/WireUI/Sources/WireSidebarUI/Views/SidebarView.swift @@ -27,6 +27,7 @@ public struct SidebarView: public var accountInfo: SidebarAccountInfo? @Binding public var selectedMenuItem: SidebarSelectableMenuItem public var showUnreadFilters: Bool + public var showMeetings: Bool private(set) var accountImageAction: () -> Void private(set) var foldersAction: (CGRect) -> Void @@ -44,6 +45,7 @@ public struct SidebarView: accountInfo: SidebarAccountInfo, selectedMenuItem: Binding, showUnreadFilters: Bool, + showMeetings: Bool, accountImageAction: @escaping () -> Void, foldersAction: @escaping (_ buttonFrame: CGRect) -> Void, supportAction: @escaping () -> Void, @@ -53,6 +55,7 @@ public struct SidebarView: self.accountInfo = accountInfo _selectedMenuItem = selectedMenuItem self.showUnreadFilters = showUnreadFilters + self.showMeetings = showMeetings self.accountImageAction = accountImageAction self.foldersAction = foldersAction self.supportAction = supportAction @@ -137,6 +140,12 @@ public struct SidebarView: // Additional filters selectableMenuItem(.folders) selectableMenuItem(.archive) + + // Meetings + if showMeetings { + menuItemHeader(Strings.Meetings.title, addTopPadding: false) + selectableMenuItem(.meetings) + } } .padding(.horizontal, 16) } @@ -262,6 +271,11 @@ public struct SidebarView: icon = "archivebox" accessibilityLabel = Text(Strings.ConversationFilter.Archived.title) + case .meetings: + text = Text(Strings.Meetings.AllMeetings.title) + icon = "video" + accessibilityLabel = Text(Strings.Meetings.AllMeetings.title) + case .settings: text = Text(Strings.Settings.title) icon = "gearshape" diff --git a/WireUI/Sources/WireSidebarUI/Views/SidebarViewController.swift b/WireUI/Sources/WireSidebarUI/Views/SidebarViewController.swift index a007a543590..0b3abe8afc6 100644 --- a/WireUI/Sources/WireSidebarUI/Views/SidebarViewController.swift +++ b/WireUI/Sources/WireSidebarUI/Views/SidebarViewController.swift @@ -94,6 +94,11 @@ public final class SidebarViewController: UIViewController { set { model.showUnreadFilters = newValue } } + public var showMeetings: Bool { + get { model.showMeetings } + set { model.showMeetings = newValue } + } + // MARK: - Private Properties private var model: SidebarModel! @@ -176,6 +181,7 @@ private struct SidebarAdapter