mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 18:21:00 +00:00
Add secondary column when screen is wide enough
This commit is contained in:
parent
243cbcbc41
commit
497c2a1fe1
5 changed files with 57 additions and 42 deletions
|
@ -12,9 +12,9 @@ import Timeline
|
||||||
@main
|
@main
|
||||||
struct IceCubesApp: App {
|
struct IceCubesApp: App {
|
||||||
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
|
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
|
||||||
|
|
||||||
@Environment(\.scenePhase) private var scenePhase
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
|
|
||||||
@StateObject private var appAccountsManager = AppAccountsManager.shared
|
@StateObject private var appAccountsManager = AppAccountsManager.shared
|
||||||
@StateObject private var currentInstance = CurrentInstance.shared
|
@StateObject private var currentInstance = CurrentInstance.shared
|
||||||
@StateObject private var currentAccount = CurrentAccount.shared
|
@StateObject private var currentAccount = CurrentAccount.shared
|
||||||
|
@ -23,18 +23,18 @@ struct IceCubesApp: App {
|
||||||
@StateObject private var quickLook = QuickLook()
|
@StateObject private var quickLook = QuickLook()
|
||||||
@StateObject private var theme = Theme.shared
|
@StateObject private var theme = Theme.shared
|
||||||
@StateObject private var sidebarRouterPath = RouterPath()
|
@StateObject private var sidebarRouterPath = RouterPath()
|
||||||
|
|
||||||
@State private var selectedTab: Tab = .timeline
|
@State private var selectedTab: Tab = .timeline
|
||||||
@State private var selectSidebarItem: Tab? = .timeline
|
@State private var selectSidebarItem: Tab? = .timeline
|
||||||
@State private var popToRootTab: Tab = .other
|
@State private var popToRootTab: Tab = .other
|
||||||
@State private var sideBarLoadedTabs: Set<Tab> = Set()
|
@State private var sideBarLoadedTabs: Set<Tab> = Set()
|
||||||
|
|
||||||
private let feedbackGenerator = UISelectionFeedbackGenerator()
|
private let feedbackGenerator = UISelectionFeedbackGenerator()
|
||||||
|
|
||||||
private var availableTabs: [Tab] {
|
private var availableTabs: [Tab] {
|
||||||
appAccountsManager.currentClient.isAuth ? Tab.loggedInTabs() : Tab.loggedOutTab()
|
appAccountsManager.currentClient.isAuth ? Tab.loggedInTabs() : Tab.loggedOutTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
appView
|
appView
|
||||||
|
@ -72,7 +72,7 @@ struct IceCubesApp: App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var appView: some View {
|
private var appView: some View {
|
||||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||||
|
@ -81,35 +81,45 @@ struct IceCubesApp: App {
|
||||||
tabBarView
|
tabBarView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func badgeFor(tab: Tab) -> Int {
|
private func badgeFor(tab: Tab) -> Int {
|
||||||
if tab == .notifications && selectedTab != tab {
|
if tab == .notifications && selectedTab != tab {
|
||||||
return watcher.unreadNotificationsCount + userPreferences.pushNotificationsCount
|
return watcher.unreadNotificationsCount + userPreferences.pushNotificationsCount
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private var sidebarView: some View {
|
private var sidebarView: some View {
|
||||||
SideBarView(selectedTab: $selectedTab,
|
SideBarView(selectedTab: $selectedTab,
|
||||||
popToRootTab: $popToRootTab,
|
popToRootTab: $popToRootTab,
|
||||||
tabs: availableTabs,
|
tabs: availableTabs,
|
||||||
routerPath: sidebarRouterPath) {
|
routerPath: sidebarRouterPath) {
|
||||||
ZStack {
|
GeometryReader { proxy in
|
||||||
if selectedTab == .profile {
|
HStack(spacing: 0) {
|
||||||
ProfileTab(popToRootTab: $popToRootTab)
|
ZStack {
|
||||||
}
|
if selectedTab == .profile {
|
||||||
ForEach(availableTabs) { tab in
|
ProfileTab(popToRootTab: $popToRootTab)
|
||||||
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
|
}
|
||||||
tab
|
ForEach(availableTabs) { tab in
|
||||||
.makeContentView(popToRootTab: $popToRootTab)
|
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
|
||||||
.opacity(tab == selectedTab ? 1 : 0)
|
tab
|
||||||
.transition(.opacity)
|
.makeContentView(popToRootTab: $popToRootTab)
|
||||||
.id("\(tab)\(appAccountsManager.currentAccount.id)")
|
.opacity(tab == selectedTab ? 1 : 0)
|
||||||
.onAppear {
|
.transition(.opacity)
|
||||||
sideBarLoadedTabs.insert(tab)
|
.id("\(tab)\(appAccountsManager.currentAccount.id)")
|
||||||
|
.onAppear {
|
||||||
|
sideBarLoadedTabs.insert(tab)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
EmptyView()
|
}
|
||||||
|
if proxy.frame(in: .global).width > (.maxColumnWidth + .secondaryColumnWidth),
|
||||||
|
currentAccount.account?.id != nil {
|
||||||
|
Divider().edgesIgnoringSafeArea(.all)
|
||||||
|
NotificationsTab(popToRootTab: $popToRootTab, lockedType: nil, isSecondaryColumn: true)
|
||||||
|
.frame(maxWidth: 360)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,7 +127,7 @@ struct IceCubesApp: App {
|
||||||
sideBarLoadedTabs.removeAll()
|
sideBarLoadedTabs.removeAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var tabBarView: some View {
|
private var tabBarView: some View {
|
||||||
TabView(selection: .init(get: {
|
TabView(selection: .init(get: {
|
||||||
selectedTab
|
selectedTab
|
||||||
|
@ -143,14 +153,14 @@ struct IceCubesApp: App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setNewClientsInEnv(client: Client) {
|
private func setNewClientsInEnv(client: Client) {
|
||||||
currentAccount.setClient(client: client)
|
currentAccount.setClient(client: client)
|
||||||
currentInstance.setClient(client: client)
|
currentInstance.setClient(client: client)
|
||||||
userPreferences.setClient(client: client)
|
userPreferences.setClient(client: client)
|
||||||
watcher.setClient(client: client)
|
watcher.setClient(client: client)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleScenePhase(scenePhase: ScenePhase) {
|
private func handleScenePhase(scenePhase: ScenePhase) {
|
||||||
switch scenePhase {
|
switch scenePhase {
|
||||||
case .background:
|
case .background:
|
||||||
|
@ -167,16 +177,16 @@ struct IceCubesApp: App {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupRevenueCat() {
|
private func setupRevenueCat() {
|
||||||
Purchases.logLevel = .error
|
Purchases.logLevel = .error
|
||||||
Purchases.configure(withAPIKey: "appl_JXmiRckOzXXTsHKitQiicXCvMQi")
|
Purchases.configure(withAPIKey: "appl_JXmiRckOzXXTsHKitQiicXCvMQi")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func refreshPushSubs() {
|
private func refreshPushSubs() {
|
||||||
PushNotificationsService.shared.requestPushNotifications()
|
PushNotificationsService.shared.requestPushNotifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
@CommandsBuilder
|
@CommandsBuilder
|
||||||
private var appMenu: some Commands {
|
private var appMenu: some Commands {
|
||||||
CommandGroup(replacing: .newItem) {
|
CommandGroup(replacing: .newItem) {
|
||||||
|
@ -203,14 +213,14 @@ struct IceCubesApp: App {
|
||||||
|
|
||||||
class AppDelegate: NSObject, UIApplicationDelegate {
|
class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
let themeObserver = ThemeObserverViewController(nibName: nil, bundle: nil)
|
let themeObserver = ThemeObserverViewController(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
func application(_: UIApplication,
|
func application(_: UIApplication,
|
||||||
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
|
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
|
||||||
{
|
{
|
||||||
try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
|
try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func application(_: UIApplication,
|
func application(_: UIApplication,
|
||||||
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
|
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
|
||||||
{
|
{
|
||||||
|
@ -220,9 +230,9 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
await PushNotificationsService.shared.updateSubscriptions(forceCreate: false)
|
await PushNotificationsService.shared.updateSubscriptions(forceCreate: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {}
|
func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {}
|
||||||
|
|
||||||
func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||||
let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
|
let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
|
||||||
if connectingSceneSession.role == .windowApplication {
|
if connectingSceneSession.role == .windowApplication {
|
||||||
|
@ -235,7 +245,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
class ThemeObserverViewController: UIViewController {
|
class ThemeObserverViewController: UIViewController {
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
super.traitCollectionDidChange(previousTraitCollection)
|
||||||
|
|
||||||
print(traitCollection.userInterfaceStyle.rawValue)
|
print(traitCollection.userInterfaceStyle.rawValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct NotificationsTab: View {
|
||||||
@Binding var popToRootTab: Tab
|
@Binding var popToRootTab: Tab
|
||||||
|
|
||||||
let lockedType: Models.Notification.NotificationType?
|
let lockedType: Models.Notification.NotificationType?
|
||||||
|
let isSecondaryColumn: Bool
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $routerPath.path) {
|
NavigationStack(path: $routerPath.path) {
|
||||||
|
@ -25,11 +26,13 @@ struct NotificationsTab: View {
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
statusEditorToolbarItem(routerPath: routerPath,
|
if !isSecondaryColumn {
|
||||||
visibility: userPreferences.postVisibility)
|
statusEditorToolbarItem(routerPath: routerPath,
|
||||||
if UIDevice.current.userInterfaceIdiom != .pad {
|
visibility: userPreferences.postVisibility)
|
||||||
ToolbarItem(placement: .navigationBarLeading) {
|
if UIDevice.current.userInterfaceIdiom != .pad {
|
||||||
AppAccountsSelectorView(routerPath: routerPath)
|
ToolbarItem(placement: .navigationBarLeading) {
|
||||||
|
AppAccountsSelectorView(routerPath: routerPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ enum Tab: Int, Identifiable, Hashable {
|
||||||
case .federated:
|
case .federated:
|
||||||
TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
|
TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
|
||||||
case .notifications:
|
case .notifications:
|
||||||
NotificationsTab(popToRootTab: popToRootTab, lockedType: nil)
|
NotificationsTab(popToRootTab: popToRootTab, lockedType: nil, isSecondaryColumn: false)
|
||||||
case .mentions:
|
case .mentions:
|
||||||
NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention)
|
NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention, isSecondaryColumn: false)
|
||||||
case .explore:
|
case .explore:
|
||||||
ExploreTab(popToRootTab: popToRootTab)
|
ExploreTab(popToRootTab: popToRootTab)
|
||||||
case .messages:
|
case .messages:
|
||||||
|
|
|
@ -5,6 +5,7 @@ public extension CGFloat {
|
||||||
static let dividerPadding: CGFloat = 2
|
static let dividerPadding: CGFloat = 2
|
||||||
static let statusColumnsSpacing: CGFloat = 8
|
static let statusColumnsSpacing: CGFloat = 8
|
||||||
static let maxColumnWidth: CGFloat = 650
|
static let maxColumnWidth: CGFloat = 650
|
||||||
|
static let secondaryColumnWidth: CGFloat = 360
|
||||||
static let sidebarWidth: CGFloat = 80
|
static let sidebarWidth: CGFloat = 80
|
||||||
static let pollBarHeight: CGFloat = 30
|
static let pollBarHeight: CGFloat = 30
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,6 +319,7 @@ public struct StatusRowView: View {
|
||||||
Text("status.action.translate")
|
Text("status.action.translate")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let translation = viewModel.translation, !viewModel.isLoadingTranslation {
|
if let translation = viewModel.translation, !viewModel.isLoadingTranslation {
|
||||||
|
|
Loading…
Reference in a new issue