Refactor App level to App + App View -> Slideover = phone layout on iPad

This commit is contained in:
Thomas Ricouard 2023-12-29 18:50:53 +01:00
parent 84898c3b8e
commit c328c6c0be
14 changed files with 195 additions and 182 deletions

View File

@ -58,6 +58,8 @@
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; }; 9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; };
9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; }; 9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; };
9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; }; 9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; };
9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; };
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028572B3F3B7600476078 /* ToolbarTab.swift */; };
9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F654BEE299AC45B00D27FA5 /* ReportView.swift */; }; 9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F654BEE299AC45B00D27FA5 /* ReportView.swift */; };
9F7335EA2966B3F800AFF0BA /* Conversations in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7335E92966B3F800AFF0BA /* Conversations */; }; 9F7335EA2966B3F800AFF0BA /* Conversations in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7335E92966B3F800AFF0BA /* Conversations */; };
9F7335ED2967463400AFF0BA /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7335EB2967461B00AFF0BA /* AVKit.framework */; }; 9F7335ED2967463400AFF0BA /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7335EB2967461B00AFF0BA /* AVKit.framework */; };
@ -84,8 +86,6 @@
9FB143D12983104700A27BB1 /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; }; 9FB143D12983104700A27BB1 /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; };
9FB143D22983104A00A27BB1 /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; }; 9FB143D22983104A00A27BB1 /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; };
9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */; }; 9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */; };
9FB183252AE926E900BBB692 /* IceCubesApp+Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183242AE926E900BBB692 /* IceCubesApp+Sidebar.swift */; };
9FB183272AE9279F00BBB692 /* IceCubesApp+Tabbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183262AE9279F00BBB692 /* IceCubesApp+Tabbar.swift */; };
9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */; }; 9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */; };
9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; }; 9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; };
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; }; 9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; };
@ -206,6 +206,8 @@
9F55C68C2955968700F94077 /* ExploreTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreTab.swift; sourceTree = "<group>"; }; 9F55C68C2955968700F94077 /* ExploreTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreTab.swift; sourceTree = "<group>"; };
9F55C68E295598F900F94077 /* Explore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Explore; path = Packages/Explore; sourceTree = "<group>"; }; 9F55C68E295598F900F94077 /* Explore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Explore; path = Packages/Explore; sourceTree = "<group>"; };
9F5E581729545B5500A53960 /* Env */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Env; path = Packages/Env; sourceTree = "<group>"; }; 9F5E581729545B5500A53960 /* Env */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Env; path = Packages/Env; sourceTree = "<group>"; };
9F6028552B3F36AE00476078 /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
9F6028572B3F3B7600476078 /* ToolbarTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTab.swift; sourceTree = "<group>"; };
9F62216829A68DA4007B77CA /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 9F62216829A68DA4007B77CA /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
9F654BEE299AC45B00D27FA5 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; }; 9F654BEE299AC45B00D27FA5 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; };
9F7335E82966B3DC00AFF0BA /* Conversations */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Conversations; path = Packages/Conversations; sourceTree = "<group>"; }; 9F7335E82966B3DC00AFF0BA /* Conversations */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Conversations; path = Packages/Conversations; sourceTree = "<group>"; };
@ -225,8 +227,6 @@
9FAE4AC8293774FF00772766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 9FAE4AC8293774FF00772766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
9FAE4ACA293783B000772766 /* SettingsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTab.swift; sourceTree = "<group>"; }; 9FAE4ACA293783B000772766 /* SettingsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTab.swift; sourceTree = "<group>"; };
9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Menu.swift"; sourceTree = "<group>"; }; 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Menu.swift"; sourceTree = "<group>"; };
9FB183242AE926E900BBB692 /* IceCubesApp+Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Sidebar.swift"; sourceTree = "<group>"; };
9FB183262AE9279F00BBB692 /* IceCubesApp+Tabbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Tabbar.swift"; sourceTree = "<group>"; };
9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Scene.swift"; sourceTree = "<group>"; }; 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Scene.swift"; sourceTree = "<group>"; };
9FBFE639292A715500C250E9 /* Ice Cubes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ice Cubes.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9FBFE639292A715500C250E9 /* Ice Cubes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ice Cubes.app"; sourceTree = BUILT_PRODUCTS_DIR; };
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; }; 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; };
@ -432,6 +432,7 @@
9F4A48182976B21900A1A038 /* ProfileTab.swift */, 9F4A48182976B21900A1A038 /* ProfileTab.swift */,
9F15D5FF2B3D6A850008C220 /* NavigationTab.swift */, 9F15D5FF2B3D6A850008C220 /* NavigationTab.swift */,
9F15D6032B3DC2180008C220 /* NavigationSheet.swift */, 9F15D6032B3DC2180008C220 /* NavigationSheet.swift */,
9F6028572B3F3B7600476078 /* ToolbarTab.swift */,
); );
path = Tabs; path = Tabs;
sourceTree = "<group>"; sourceTree = "<group>";
@ -441,9 +442,8 @@
children = ( children = (
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */, 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */,
9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */, 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */,
9FB183242AE926E900BBB692 /* IceCubesApp+Sidebar.swift */,
9FB183262AE9279F00BBB692 /* IceCubesApp+Tabbar.swift */,
9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */, 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */,
9F6028552B3F36AE00476078 /* AppView.swift */,
); );
path = Main; path = Main;
sourceTree = "<group>"; sourceTree = "<group>";
@ -822,14 +822,12 @@
files = ( files = (
9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */, 9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */,
9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */, 9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */,
9FB183252AE926E900BBB692 /* IceCubesApp+Sidebar.swift in Sources */,
9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */, 9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */,
069709AA298C9AD7006E4CB5 /* AboutView.swift in Sources */, 069709AA298C9AD7006E4CB5 /* AboutView.swift in Sources */,
9F2B92FC295DA94500DE16D0 /* InstanceInfoView.swift in Sources */, 9F2B92FC295DA94500DE16D0 /* InstanceInfoView.swift in Sources */,
C9B22677297F6C2E001F9EFE /* ContentSettingsView.swift in Sources */, C9B22677297F6C2E001F9EFE /* ContentSettingsView.swift in Sources */,
9F15D6042B3DC2180008C220 /* NavigationSheet.swift in Sources */, 9F15D6042B3DC2180008C220 /* NavigationSheet.swift in Sources */,
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */, 9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */,
9FB183272AE9279F00BBB692 /* IceCubesApp+Tabbar.swift in Sources */,
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */, 9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */,
9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */, 9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */,
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */, 9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
@ -850,9 +848,11 @@
9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */, 9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */,
D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */, D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */,
9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */, 9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */,
9F6028562B3F36AE00476078 /* AppView.swift in Sources */,
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */, 9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */,
9F1E8B47298EBCBB00609F80 /* HapticSettingsView.swift in Sources */, 9F1E8B47298EBCBB00609F80 /* HapticSettingsView.swift in Sources */,
9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */, 9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */,
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -0,0 +1,135 @@
import Account
import AppAccount
import AVFoundation
import DesignSystem
import Env
import KeychainSwift
import MediaUI
import Network
import RevenueCat
import Status
import SwiftUI
import Timeline
@MainActor
struct AppView: View {
@Environment(AppAccountsManager.self) private var appAccountsManager
@Environment(UserPreferences.self) private var userPreferences
@Environment(Theme.self) private var theme
@Environment(StreamWatcher.self) private var watcher
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Binding var selectedTab: Tab
@Binding var sidebarRouterPath: RouterPath
@State var popToRootTab: Tab = .other
@State var iosTabs = iOSTabs.shared
@State var sideBarLoadedTabs: Set<Tab> = Set()
var body: some View {
if (UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac) &&
horizontalSizeClass == .regular {
sidebarView
} else {
tabBarView
}
}
var availableTabs: [Tab] {
if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact {
return appAccountsManager.currentClient.isAuth ? iosTabs.tabs : Tab.loggedOutTab()
}
return appAccountsManager.currentClient.isAuth ? Tab.loggedInTabs() : Tab.loggedOutTab()
}
var tabBarView: some View {
TabView(selection: .init(get: {
selectedTab
}, set: { newTab in
if newTab == selectedTab {
/// Stupid hack to trigger onChange binding in tab views.
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = selectedTab
}
}
HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection)
selectedTab = newTab
})) {
ForEach(availableTabs) { tab in
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.tabItem {
if userPreferences.showiPhoneTabLabel {
tab.label
} else {
Image(systemName: tab.iconName)
}
}
.tag(tab)
.badge(badgeFor(tab: tab))
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .tabBar)
}
}
.id(appAccountsManager.currentClient.id)
}
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications, selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + (userPreferences.notificationsCount[token] ?? 0)
}
return 0
}
var sidebarView: some View {
SideBarView(selectedTab: $selectedTab,
popToRootTab: $popToRootTab,
tabs: availableTabs)
{
HStack(spacing: 0) {
ZStack {
if selectedTab == .profile {
ProfileTab(popToRootTab: $popToRootTab)
}
ForEach(availableTabs) { tab in
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
tab
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.opacity(tab == selectedTab ? 1 : 0)
.transition(.opacity)
.id("\(tab)\(appAccountsManager.currentAccount.id)")
.onAppear {
sideBarLoadedTabs.insert(tab)
}
} else {
EmptyView()
}
}
}
if appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
}
}
}.onChange(of: appAccountsManager.currentAccount.id) {
sideBarLoadedTabs.removeAll()
}
.environment(sidebarRouterPath)
}
var notificationsSecondaryColumn: some View {
NotificationsTab(selectedTab: .constant(.notifications),
popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true)
.frame(maxWidth: .secondaryColumnWidth)
.id(appAccountsManager.currentAccount.id)
}
}

View File

@ -6,7 +6,7 @@ import SwiftUI
extension IceCubesApp { extension IceCubesApp {
var appScene: some Scene { var appScene: some Scene {
WindowGroup(id: "MainWindow") { WindowGroup(id: "MainWindow") {
appView AppView(selectedTab: $selectedTab, sidebarRouterPath: $sidebarRouterPath)
.applyTheme(theme) .applyTheme(theme)
.onAppear { .onAppear {
setNewClientsInEnv(client: appAccountsManager.currentClient) setNewClientsInEnv(client: appAccountsManager.currentClient)
@ -63,15 +63,6 @@ extension IceCubesApp {
} }
} }
@ViewBuilder
private var appView: some View {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
sidebarView
} else {
tabBarView
}
}
@SceneBuilder @SceneBuilder
var otherScenes: some Scene { var otherScenes: some Scene {
WindowGroup(for: WindowDestinationEditor.self) { destination in WindowGroup(for: WindowDestinationEditor.self) { destination in

View File

@ -1,50 +0,0 @@
import Env
import SwiftUI
extension IceCubesApp {
var sidebarView: some View {
SideBarView(selectedTab: $selectedTab,
popToRootTab: $popToRootTab,
tabs: availableTabs)
{
HStack(spacing: 0) {
ZStack {
if selectedTab == .profile {
ProfileTab(popToRootTab: $popToRootTab)
}
ForEach(availableTabs) { tab in
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
tab
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.opacity(tab == selectedTab ? 1 : 0)
.transition(.opacity)
.id("\(tab)\(appAccountsManager.currentAccount.id)")
.onAppear {
sideBarLoadedTabs.insert(tab)
}
} else {
EmptyView()
}
}
}
if appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
}
}
}.onChange(of: $appAccountsManager.currentAccount.id) {
sideBarLoadedTabs.removeAll()
}
.environment(sidebarRouterPath)
}
var notificationsSecondaryColumn: some View {
NotificationsTab(selectedTab: .constant(.notifications),
popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true)
.frame(maxWidth: .secondaryColumnWidth)
.id(appAccountsManager.currentAccount.id)
}
}

View File

@ -1,47 +0,0 @@
import Env
import SwiftUI
extension IceCubesApp {
var tabBarView: some View {
TabView(selection: .init(get: {
selectedTab
}, set: { newTab in
if newTab == selectedTab {
/// Stupid hack to trigger onChange binding in tab views.
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = selectedTab
}
}
HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection)
selectedTab = newTab
})) {
ForEach(availableTabs) { tab in
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.tabItem {
if userPreferences.showiPhoneTabLabel {
tab.label
} else {
Image(systemName: tab.iconName)
}
}
.tag(tab)
.badge(badgeFor(tab: tab))
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .tabBar)
}
}
.id(appAccountsManager.currentClient.id)
}
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications, selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + (userPreferences.notificationsCount[token] ?? 0)
}
return 0
}
}

View File

@ -26,21 +26,12 @@ struct IceCubesApp: App {
@State var watcher = StreamWatcher() @State var watcher = StreamWatcher()
@State var quickLook = QuickLook.shared @State var quickLook = QuickLook.shared
@State var theme = Theme.shared @State var theme = Theme.shared
@State var sidebarRouterPath = RouterPath()
@State var selectedTab: Tab = .timeline @State var selectedTab: Tab = .timeline
@State var popToRootTab: Tab = .other @State var sidebarRouterPath = RouterPath()
@State var iosTabs = iOSTabs.shared
@State var sideBarLoadedTabs: Set<Tab> = Set()
@State var isSupporter: Bool = false @State var isSupporter: Bool = false
var availableTabs: [Tab] {
if UIDevice.current.userInterfaceIdiom == .phone {
return appAccountsManager.currentClient.isAuth ? iosTabs.tabs : Tab.loggedOutTab()
}
return appAccountsManager.currentClient.isAuth ? Tab.loggedInTabs() : Tab.loggedOutTab()
}
var body: some Scene { var body: some Scene {
appScene appScene
otherScenes otherScenes

View File

@ -24,16 +24,7 @@ struct ExploreTab: View {
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar)
.toolbar { .toolbar {
statusEditorToolbarItem(routerPath: routerPath, ToolbarTab(routerPath: $routerPath)
visibility: preferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad {
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
}
}
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
} }
} }
.withSafariRouter() .withSafariRouter()

View File

@ -25,11 +25,7 @@ struct MessagesTab: View {
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {
if UIDevice.current.userInterfaceIdiom != .pad { ToolbarTab(routerPath: $routerPath)
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
}
}
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar)
.id(client.id) .id(client.id)

View File

@ -27,20 +27,7 @@ struct NavigationTab<Content: View>: View {
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {
if !isSecondaryColumn { ToolbarTab(routerPath: $routerPath)
statusEditorToolbarItem(routerPath: routerPath,
visibility: userPreferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad {
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
}
}
}
if UIDevice.current.userInterfaceIdiom == .pad {
if (!isSecondaryColumn && !userPreferences.showiPadSecondaryColumn) || isSecondaryColumn {
SecondaryColumnToolbarItem()
}
}
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar)
} }

View File

@ -40,20 +40,7 @@ struct NotificationsTab: View {
Image(systemName: "bell.badge") Image(systemName: "bell.badge")
} }
} }
if !isSecondaryColumn { ToolbarTab(routerPath: $routerPath)
statusEditorToolbarItem(routerPath: routerPath,
visibility: userPreferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad {
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
}
}
}
if UIDevice.current.userInterfaceIdiom == .pad {
if (!isSecondaryColumn && !userPreferences.showiPadSecondaryColumn) || isSecondaryColumn {
SecondaryColumnToolbarItem()
}
}
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar)
.id(client.id) .id(client.id)

View File

@ -14,6 +14,7 @@ import Timeline
struct SettingsTabs: View { struct SettingsTabs: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var context @Environment(\.modelContext) private var context
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(PushNotificationsService.self) private var pushNotifications @Environment(PushNotificationsService.self) private var pushNotifications
@Environment(UserPreferences.self) private var preferences @Environment(UserPreferences.self) private var preferences
@ -160,7 +161,7 @@ struct SettingsTabs: View {
NavigationLink(destination: SwipeActionsSettingsView()) { NavigationLink(destination: SwipeActionsSettingsView()) {
Label("settings.general.swipeactions", systemImage: "hand.draw") Label("settings.general.swipeactions", systemImage: "hand.draw")
} }
if UIDevice.current.userInterfaceIdiom == .phone { if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact {
NavigationLink(destination: TabbarEntriesSettingsView()) { NavigationLink(destination: TabbarEntriesSettingsView()) {
Label("settings.general.tabbarEntries", systemImage: "platter.filled.bottom.iphone") Label("settings.general.tabbarEntries", systemImage: "platter.filled.bottom.iphone")
} }

View File

@ -228,17 +228,7 @@ struct TimelineTab: View {
} }
} }
if client.isAuth { if client.isAuth {
if UIDevice.current.userInterfaceIdiom != .pad { ToolbarTab(routerPath: $routerPath)
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
.id(currentAccount.account?.id)
}
}
statusEditorToolbarItem(routerPath: routerPath,
visibility: preferences.postVisibility)
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
} else { } else {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
addAccountButton addAccountButton

View File

@ -0,0 +1,32 @@
import SwiftUI
import Env
import AppAccount
import DesignSystem
@MainActor
struct ToolbarTab: ToolbarContent {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(UserPreferences.self) private var userPreferences
@Binding var routerPath: RouterPath
var body: some ToolbarContent {
if !isSecondaryColumn {
statusEditorToolbarItem(routerPath: routerPath,
visibility: userPreferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad ||
(UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact) {
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath)
}
}
}
if UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .regular {
if (!isSecondaryColumn && !userPreferences.showiPadSecondaryColumn) || isSecondaryColumn {
SecondaryColumnToolbarItem()
}
}
}
}

View File

@ -11,6 +11,15 @@ public extension View {
} }
} }
@MainActor
public extension ToolbarContent {
func statusEditorToolbarItem(routerPath _: RouterPath,
visibility: Models.Visibility) -> some ToolbarContent
{
StatusEditorToolbarItem(visibility: visibility)
}
}
@MainActor @MainActor
public struct StatusEditorToolbarItem: ToolbarContent { public struct StatusEditorToolbarItem: ToolbarContent {
@Environment(\.openWindow) private var openWindow @Environment(\.openWindow) private var openWindow