2022-12-29 08:06:21 +01:00
|
|
|
//
|
|
|
|
// https://mczachurski.dev
|
|
|
|
// Copyright © 2022 Marcin Czachurski and the repository contributors.
|
|
|
|
// Licensed under the MIT License.
|
|
|
|
//
|
|
|
|
|
|
|
|
import SwiftUI
|
|
|
|
import UIKit
|
|
|
|
import CoreData
|
2023-02-19 10:32:38 +01:00
|
|
|
import PixelfedKit
|
2022-12-29 08:06:21 +01:00
|
|
|
|
2023-02-22 20:53:44 +01:00
|
|
|
struct MainView: View {
|
2022-12-29 08:06:21 +01:00
|
|
|
@Environment(\.managedObjectContext) private var viewContext
|
2023-02-03 15:16:30 +01:00
|
|
|
|
2022-12-30 18:20:54 +01:00
|
|
|
@EnvironmentObject var applicationState: ApplicationState
|
2023-02-03 15:16:30 +01:00
|
|
|
@EnvironmentObject var client: Client
|
2023-01-23 18:01:27 +01:00
|
|
|
@EnvironmentObject var routerPath: RouterPath
|
2023-02-14 07:32:00 +01:00
|
|
|
@EnvironmentObject var tipsStore: TipsStore
|
2023-01-12 18:34:48 +01:00
|
|
|
|
2022-12-30 18:20:54 +01:00
|
|
|
@State private var navBarTitle: String = "Home"
|
|
|
|
@State private var viewMode: ViewMode = .home {
|
|
|
|
didSet {
|
2022-12-31 16:31:05 +01:00
|
|
|
self.navBarTitle = self.getViewTitle(viewMode: viewMode)
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-29 17:27:15 +01:00
|
|
|
|
2023-01-11 13:16:43 +01:00
|
|
|
@FetchRequest(sortDescriptors: [SortDescriptor(\.acct, order: .forward)]) var dbAccounts: FetchedResults<AccountData>
|
|
|
|
|
2022-12-30 18:20:54 +01:00
|
|
|
private enum ViewMode {
|
2023-01-23 11:42:28 +01:00
|
|
|
case home, local, federated, profile, notifications, trending
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
2022-12-29 08:06:21 +01:00
|
|
|
|
|
|
|
var body: some View {
|
2022-12-30 18:20:54 +01:00
|
|
|
self.getMainView()
|
2023-02-21 08:36:14 +01:00
|
|
|
.navigationTitle(navBarTitle)
|
2022-12-30 18:20:54 +01:00
|
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
|
|
.toolbar {
|
|
|
|
self.getLeadingToolbar()
|
|
|
|
self.getPrincipalToolbar()
|
2023-01-12 18:34:48 +01:00
|
|
|
self.getTrailingToolbar()
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
2023-02-14 07:32:00 +01:00
|
|
|
.onChange(of: tipsStore.status) { status in
|
|
|
|
if status == .successful {
|
2023-02-13 21:10:07 +01:00
|
|
|
withAnimation(.spring()) {
|
|
|
|
self.routerPath.presentedOverlay = .successPayment
|
2023-02-14 07:32:00 +01:00
|
|
|
self.tipsStore.reset()
|
2023-02-13 21:10:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@ViewBuilder
|
|
|
|
private func getMainView() -> some View {
|
|
|
|
switch self.viewMode {
|
|
|
|
case .home:
|
2023-01-31 12:20:49 +01:00
|
|
|
HomeFeedView(accountId: applicationState.account?.id ?? String.empty())
|
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2023-01-23 11:42:28 +01:00
|
|
|
case .trending:
|
2023-01-31 12:20:49 +01:00
|
|
|
TrendStatusesView(accountId: applicationState.account?.id ?? String.empty())
|
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2022-12-30 18:20:54 +01:00
|
|
|
case .local:
|
2023-01-23 18:01:27 +01:00
|
|
|
StatusesView(listType: .local)
|
2023-01-31 12:20:49 +01:00
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2022-12-30 18:20:54 +01:00
|
|
|
case .federated:
|
2023-01-23 18:01:27 +01:00
|
|
|
StatusesView(listType: .federated)
|
2023-01-31 12:20:49 +01:00
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2023-01-05 21:08:19 +01:00
|
|
|
case .profile:
|
2023-01-31 12:20:49 +01:00
|
|
|
if let accountData = self.applicationState.account {
|
2023-01-05 21:08:19 +01:00
|
|
|
UserProfileView(accountId: accountData.id,
|
|
|
|
accountDisplayName: accountData.displayName,
|
2023-01-06 13:05:21 +01:00
|
|
|
accountUserName: accountData.acct)
|
2023-01-31 12:20:49 +01:00
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2023-01-05 21:08:19 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
case .notifications:
|
2023-01-31 12:20:49 +01:00
|
|
|
if let accountData = self.applicationState.account {
|
2023-01-18 18:41:42 +01:00
|
|
|
NotificationsView(accountId: accountData.id)
|
2023-01-31 12:20:49 +01:00
|
|
|
.id(applicationState.account?.id ?? String.empty())
|
2023-01-18 18:41:42 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ToolbarContentBuilder
|
|
|
|
private func getPrincipalToolbar() -> some ToolbarContent {
|
|
|
|
ToolbarItem(placement: .principal) {
|
|
|
|
Menu {
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
2022-12-30 18:20:54 +01:00
|
|
|
viewMode = .home
|
|
|
|
} label: {
|
|
|
|
HStack {
|
2022-12-31 16:31:05 +01:00
|
|
|
Text(self.getViewTitle(viewMode: .home))
|
2022-12-30 18:20:54 +01:00
|
|
|
Image(systemName: "house")
|
2022-12-29 17:27:15 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
2022-12-30 18:20:54 +01:00
|
|
|
viewMode = .local
|
|
|
|
} label: {
|
|
|
|
HStack {
|
2022-12-31 16:31:05 +01:00
|
|
|
Text(self.getViewTitle(viewMode: .local))
|
2023-02-21 08:41:37 +01:00
|
|
|
Image(systemName: "building")
|
2022-12-29 17:27:15 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
2022-12-29 17:27:15 +01:00
|
|
|
|
2022-12-30 18:20:54 +01:00
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
2022-12-30 18:20:54 +01:00
|
|
|
viewMode = .federated
|
2022-12-29 17:27:15 +01:00
|
|
|
} label: {
|
2022-12-30 18:20:54 +01:00
|
|
|
HStack {
|
2022-12-31 16:31:05 +01:00
|
|
|
Text(self.getViewTitle(viewMode: .federated))
|
2022-12-30 18:20:54 +01:00
|
|
|
Image(systemName: "globe.europe.africa")
|
|
|
|
}
|
2022-12-29 17:27:15 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
|
2023-02-21 08:41:37 +01:00
|
|
|
Divider()
|
|
|
|
|
|
|
|
Button {
|
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
|
|
|
viewMode = .trending
|
|
|
|
} label: {
|
|
|
|
HStack {
|
|
|
|
Text(self.getViewTitle(viewMode: .trending))
|
|
|
|
Image(systemName: "chart.line.uptrend.xyaxis")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-03 20:42:20 +01:00
|
|
|
Divider()
|
2023-01-05 21:08:19 +01:00
|
|
|
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
2023-01-05 21:08:19 +01:00
|
|
|
viewMode = .profile
|
|
|
|
} label: {
|
|
|
|
HStack {
|
|
|
|
Text(self.getViewTitle(viewMode: .profile))
|
|
|
|
Image(systemName: "person")
|
|
|
|
}
|
|
|
|
}
|
2023-01-03 20:42:20 +01:00
|
|
|
|
2022-12-29 17:27:15 +01:00
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .tabSelection)
|
2022-12-30 18:20:54 +01:00
|
|
|
viewMode = .notifications
|
2022-12-29 17:27:15 +01:00
|
|
|
} label: {
|
2022-12-30 18:20:54 +01:00
|
|
|
HStack {
|
2022-12-31 16:31:05 +01:00
|
|
|
Text(self.getViewTitle(viewMode: .notifications))
|
2022-12-30 18:20:54 +01:00
|
|
|
Image(systemName: "bell.badge")
|
2022-12-29 17:27:15 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
} label: {
|
|
|
|
HStack {
|
|
|
|
Text(navBarTitle)
|
|
|
|
.font(.headline)
|
|
|
|
Image(systemName: "chevron.down")
|
2023-02-19 10:16:01 +01:00
|
|
|
.fontWeight(.semibold)
|
2022-12-30 18:20:54 +01:00
|
|
|
.font(.subheadline)
|
|
|
|
}
|
|
|
|
.frame(width: 150)
|
2023-01-06 13:05:21 +01:00
|
|
|
.foregroundColor(.mainTextColor)
|
2022-12-29 08:06:21 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@ToolbarContentBuilder
|
|
|
|
private func getLeadingToolbar() -> some ToolbarContent {
|
|
|
|
ToolbarItem(placement: .navigationBarLeading) {
|
2023-01-03 20:42:20 +01:00
|
|
|
Menu {
|
2023-01-11 13:16:43 +01:00
|
|
|
ForEach(self.dbAccounts) { account in
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .buttonPress)
|
2023-02-12 09:13:04 +01:00
|
|
|
self.tryToSwitch(account)
|
2023-01-11 13:16:43 +01:00
|
|
|
} label: {
|
2023-01-31 12:20:49 +01:00
|
|
|
if self.applicationState.account?.id == account.id {
|
2023-01-11 13:16:43 +01:00
|
|
|
Label(account.displayName ?? account.acct, systemImage: "checkmark")
|
|
|
|
} else {
|
|
|
|
Text(account.displayName ?? account.acct)
|
|
|
|
}
|
2023-01-03 20:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Divider()
|
|
|
|
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .buttonPress)
|
2023-01-23 18:01:27 +01:00
|
|
|
self.routerPath.presentedSheet = .settings
|
2023-01-03 20:42:20 +01:00
|
|
|
} label: {
|
2023-01-11 13:16:43 +01:00
|
|
|
Label("Settings", systemImage: "gear")
|
2023-01-03 20:42:20 +01:00
|
|
|
}
|
2022-12-30 18:20:54 +01:00
|
|
|
} label: {
|
2023-01-31 12:20:49 +01:00
|
|
|
if let avatarData = self.applicationState.account?.avatarData, let uiImage = UIImage(data: avatarData) {
|
2022-12-30 18:20:54 +01:00
|
|
|
Image(uiImage: uiImage)
|
|
|
|
.resizable()
|
2023-01-24 12:22:53 +01:00
|
|
|
.clipShape(self.applicationState.avatarShape.shape())
|
2022-12-31 16:31:05 +01:00
|
|
|
.frame(width: 32.0, height: 32.0)
|
2022-12-30 18:20:54 +01:00
|
|
|
} else {
|
2023-01-24 12:22:53 +01:00
|
|
|
Image(systemName: "person")
|
2022-12-31 16:31:05 +01:00
|
|
|
.resizable()
|
2023-01-24 12:22:53 +01:00
|
|
|
.frame(width: 16, height: 16)
|
|
|
|
.foregroundColor(.white)
|
|
|
|
.padding(8)
|
|
|
|
.background(Color.lightGrayColor)
|
|
|
|
.clipShape(AvatarShape.circle.shape())
|
|
|
|
.background(
|
|
|
|
AvatarShape.circle.shape()
|
|
|
|
)
|
2022-12-30 18:20:54 +01:00
|
|
|
}
|
2022-12-29 08:06:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 18:34:48 +01:00
|
|
|
@ToolbarContentBuilder
|
|
|
|
private func getTrailingToolbar() -> some ToolbarContent {
|
2023-02-19 07:50:21 +01:00
|
|
|
if viewMode == .local || viewMode == .home || viewMode == .federated || viewMode == .trending {
|
2023-01-23 09:10:58 +01:00
|
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
|
|
Button {
|
2023-02-19 12:49:44 +01:00
|
|
|
HapticService.shared.fireHaptic(of: .buttonPress)
|
2023-01-23 18:01:27 +01:00
|
|
|
self.routerPath.presentedSheet = .newStatusEditor
|
2023-01-23 09:10:58 +01:00
|
|
|
} label: {
|
|
|
|
Image(systemName: "square.and.pencil")
|
2023-02-19 10:16:01 +01:00
|
|
|
.symbolRenderingMode(.palette)
|
|
|
|
.foregroundStyle(Color.accentColor, Color.mainTextColor)
|
|
|
|
.fontWeight(.semibold)
|
2023-01-23 09:10:58 +01:00
|
|
|
}
|
2023-01-12 18:34:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-31 16:31:05 +01:00
|
|
|
private func getViewTitle(viewMode: ViewMode) -> String {
|
|
|
|
switch viewMode {
|
|
|
|
case .home:
|
|
|
|
return "Home"
|
2023-01-23 11:42:28 +01:00
|
|
|
case .trending:
|
|
|
|
return "Trending"
|
2022-12-31 16:31:05 +01:00
|
|
|
case .local:
|
|
|
|
return "Local"
|
|
|
|
case .federated:
|
|
|
|
return "Federated"
|
2023-01-05 21:08:19 +01:00
|
|
|
case .profile:
|
|
|
|
return "Profile"
|
2022-12-31 16:31:05 +01:00
|
|
|
case .notifications:
|
|
|
|
return "Notifications"
|
2022-12-29 08:06:21 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-12 09:13:04 +01:00
|
|
|
|
|
|
|
private func tryToSwitch(_ account: AccountData) {
|
|
|
|
Task {
|
|
|
|
// Verify access token correctness.
|
|
|
|
let authorizationSession = AuthorizationSession()
|
|
|
|
await AuthorizationService.shared.verifyAccount(session: authorizationSession, currentAccount: account) { accountData in
|
|
|
|
guard let accountData = accountData else {
|
|
|
|
ToastrService.shared.showError(subtitle: "Cannot switch accounts.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
Task { @MainActor in
|
|
|
|
let accountModel = AccountModel(accountData: accountData)
|
2023-02-22 13:26:35 +01:00
|
|
|
let instance = try? await self.client.instances.instance(url: accountModel.serverUrl)
|
|
|
|
|
|
|
|
// Refresh client state.
|
2023-02-12 09:13:04 +01:00
|
|
|
self.client.setAccount(account: accountModel)
|
|
|
|
|
2023-02-22 13:26:35 +01:00
|
|
|
// Refresh application state.
|
|
|
|
self.applicationState.changeApplicationState(accountModel: accountModel,
|
|
|
|
instance: instance,
|
|
|
|
lastSeenStatusId: accountData.lastSeenStatusId)
|
|
|
|
|
|
|
|
// Set account as default (application will open this account after restart).
|
2023-02-12 09:13:04 +01:00
|
|
|
ApplicationSettingsHandler.shared.setAccountAsDefault(accountData: accountData)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-29 08:06:21 +01:00
|
|
|
}
|
|
|
|
|