2023-12-29 11:17:37 +01:00
// M a d e b y L u m a a
import Foundation
import SwiftUI
@ Observable
2024-02-16 17:26:32 +01:00
public class Navigator : ObservableObject {
2024-08-10 15:43:47 +02:00
public static var shared : Navigator = Navigator ( )
2023-12-29 11:17:37 +01:00
public var path : [ RouterDestination ] = [ ]
public var presentedSheet : SheetDestination ?
2024-02-04 08:43:56 +01:00
public var presentedCover : SheetDestination ?
2024-08-10 15:43:47 +02:00
public var selectedTab : TabDestination {
set {
change ( to : newValue )
}
get {
return self . currentTab
}
}
private var currentTab : TabDestination = . timeline
2024-08-10 17:28:15 +02:00
public var inSettings : Bool {
self . path . contains ( RouterDestination . allSettings )
}
2024-08-10 15:43:47 +02:00
public private ( set ) var memorizedNav : [ TabDestination : [ RouterDestination ] ] = [ : ]
public var showTabbar : Bool {
get {
self . visiTabbar
}
set {
withAnimation ( . spring ) {
self . visiTabbar = newValue
}
}
}
private var visiTabbar : Bool = true
2024-04-04 18:46:38 +02:00
public var client : Client ?
2023-12-29 11:17:37 +01:00
public func navigate ( to : RouterDestination ) {
path . append ( to )
}
2024-08-10 15:43:47 +02:00
// / C h a n g e s t h e c u r r e n t t a b f r o m t h e c u r r e n t ` ` N a v i g a t o r ` ` c l a s s
func change ( to tab : TabDestination ) {
savePath ( )
withAnimation ( . spring ) {
loadPath ( from : tab )
}
}
private func savePath ( ) {
let lastTab : TabDestination = self . currentTab
let lastPath : [ RouterDestination ] = self . path
memorizedNav . updateValue ( lastPath , forKey : lastTab )
}
private func loadPath ( from tab : TabDestination ) {
if let ( newTab , newPath ) = memorizedNav . first ( where : { $0 . key = = tab } ) . map ( { [ $0 . key : $0 . value ] } ) ? . first {
self . currentTab = newTab
self . path = newPath
} else {
print ( " Couldn't find Navigator data from \( tab . id ) , created new ones " )
self . currentTab = tab
self . path = [ ]
}
}
// / T h i s o n l y a p p l i e s o n t h e c u r r e n t p a t h , n o t t h e s a v e d o n e s i n ` ` m e m o r i z e d N a v ` `
2024-04-04 18:46:38 +02:00
public func removeSettingsOfPath ( ) {
self . path = self . path . filter ( { ! RouterDestination . allSettings . contains ( $0 ) } )
2024-02-17 02:06:50 +01:00
}
}
2024-02-04 08:43:56 +01:00
2024-08-10 15:43:47 +02:00
// / T h i s c a n b e u s e d f o r u n i v e r s a l ` ` S h e e t D e s t i n a t i o n ` ` s
2024-06-23 19:24:00 +02:00
public class UniversalNavigator : Navigator {
2024-08-10 15:43:47 +02:00
public static var ` static ` : UniversalNavigator = UniversalNavigator ( )
2024-06-23 19:24:00 +02:00
}
2024-04-04 18:46:38 +02:00
2023-12-29 11:17:37 +01:00
public enum TabDestination : Identifiable {
case timeline
case search
case activity
case profile
public var id : String {
switch self {
case . timeline :
return " timeline "
case . search :
return " search "
case . activity :
return " activity "
case . profile :
return " profile "
}
}
}
public enum SheetDestination : Identifiable {
case welcome
2024-01-27 08:56:22 +01:00
case shop
2024-02-18 18:39:07 +01:00
case media ( attachments : [ MediaAttachment ] , selected : MediaAttachment )
2024-01-27 08:56:22 +01:00
2023-12-29 11:17:37 +01:00
case mastodonLogin ( logged : Binding < Bool > )
2024-01-26 14:10:17 +01:00
case post ( content : String = " " , replyId : String ? = nil , editId : String ? = nil )
2024-07-30 18:43:03 +02:00
case profEdit
2024-01-21 13:08:06 +01:00
case safari ( url : URL )
2024-01-26 14:10:17 +01:00
case shareImage ( image : UIImage , status : Status )
2024-02-20 22:31:44 +01:00
case update
2024-07-05 21:06:15 +02:00
case filter
2024-08-10 02:40:41 +02:00
case reportStatus ( status : Status )
// c a s e r e p o r t U s e r
2023-12-29 11:17:37 +01:00
public var id : String {
switch self {
case . welcome :
return " welcome "
2024-01-27 08:56:22 +01:00
case . shop :
return " shop "
2024-02-18 18:39:07 +01:00
case . media :
return " media "
2024-01-27 08:56:22 +01:00
2023-12-29 11:17:37 +01:00
case . mastodonLogin :
return " login "
case . post :
return " post "
2024-07-30 18:43:03 +02:00
case . profEdit :
return " profileEdit "
2024-01-21 13:08:06 +01:00
case . safari :
return " safari "
2024-01-21 16:34:26 +01:00
case . shareImage :
return " shareImage "
2024-02-20 22:31:44 +01:00
case . update :
return " update "
2024-07-05 21:06:15 +02:00
case . filter :
return " contentfilter "
2024-08-10 02:40:41 +02:00
case . reportStatus :
return " reportStatus "
2023-12-29 11:17:37 +01:00
}
}
public var isCover : Bool {
switch self {
case . welcome :
return true
2024-01-27 08:56:22 +01:00
case . shop :
return true
2024-02-18 18:39:07 +01:00
case . media :
return true
2023-12-29 11:17:37 +01:00
case . mastodonLogin :
return false
case . post :
return false
2024-07-30 18:43:03 +02:00
case . profEdit :
return false
2024-01-21 13:08:06 +01:00
case . safari :
return false
2024-01-21 16:34:26 +01:00
case . shareImage :
return false
2024-02-20 22:31:44 +01:00
case . update :
return false
2024-07-05 21:06:15 +02:00
case . filter :
return false
2024-08-10 02:40:41 +02:00
case . reportStatus :
return false
2023-12-29 11:17:37 +01:00
}
}
}
public enum RouterDestination : Hashable {
case settings
2024-02-12 02:42:56 +01:00
case support
2024-01-04 22:19:35 +01:00
case appearence
2024-07-30 18:43:03 +02:00
case appicon
2024-03-07 23:24:44 +01:00
case about
case privacy
2024-03-23 11:16:47 +01:00
case restricted
2024-07-05 21:06:15 +02:00
case filter
2024-03-07 23:24:44 +01:00
2023-12-29 11:17:37 +01:00
case account ( acc : Account )
2024-01-10 17:45:41 +01:00
case post ( status : Status )
2024-02-10 02:22:39 +01:00
case contacts
2024-03-30 14:04:13 +01:00
case timeline ( timeline : TimelineFilter )
2023-12-29 11:17:37 +01:00
}
2024-01-28 17:51:50 +01:00
extension RouterDestination {
2024-07-30 18:43:03 +02:00
static let allSettings : [ RouterDestination ] = [ . settings , . support , . about , . appearence , . privacy , . restricted , . filter , . appicon ]
2024-01-28 17:51:50 +01:00
}
2023-12-29 11:17:37 +01:00
extension View {
2024-01-02 14:23:36 +01:00
func withAppRouter ( _ navigator : Navigator ) -> some View {
2023-12-29 11:17:37 +01:00
navigationDestination ( for : RouterDestination . self ) { destination in
switch destination {
case . settings :
2024-03-23 11:16:47 +01:00
SettingsView ( )
2024-02-12 02:42:56 +01:00
case . support :
SupportView ( )
2024-01-04 22:19:35 +01:00
case . appearence :
AppearenceView ( )
2024-07-30 18:43:03 +02:00
case . appicon :
IconView ( )
2023-12-29 11:17:37 +01:00
case . account ( let acc ) :
2024-02-04 10:44:51 +01:00
ProfileView ( account : acc )
2024-01-10 17:45:41 +01:00
case . post ( let status ) :
PostDetailsView ( status : status )
2023-12-30 20:59:09 +01:00
case . about :
AboutView ( )
2024-02-10 02:22:39 +01:00
case . contacts :
ContactsView ( )
2024-03-07 23:24:44 +01:00
case . privacy :
PrivacyView ( )
2024-03-23 11:16:47 +01:00
case . restricted :
RestrictedView ( )
2024-02-11 14:22:27 +01:00
case . timeline ( let timeline ) :
2024-03-30 14:04:13 +01:00
PostsView ( filter : timeline )
2024-07-05 21:06:15 +02:00
case . filter :
FilterView ( )
2023-12-29 11:17:37 +01:00
}
}
}
func withSheets ( sheetDestination : Binding < SheetDestination ? > ) -> some View {
sheet ( item : sheetDestination ) { destination in
2024-02-04 08:43:56 +01:00
viewSheet ( destination : destination )
2023-12-29 11:17:37 +01:00
}
}
func withCovers ( sheetDestination : Binding < SheetDestination ? > ) -> some View {
fullScreenCover ( item : sheetDestination ) { destination in
2024-02-04 08:43:56 +01:00
viewCover ( destination : destination )
2023-12-29 11:17:37 +01:00
}
}
2024-02-04 08:43:56 +01:00
private func viewCover ( destination : SheetDestination ) -> some View {
Group {
switch destination {
case . welcome :
ConnectView ( )
case . shop :
ShopView ( )
2024-02-18 18:39:07 +01:00
case . media ( let attachments , let selected ) :
AttachmentView ( attachments : attachments , selectedId : selected . id )
2024-02-04 08:43:56 +01:00
default :
EmptySheetView ( destId : destination . id )
}
}
}
private func viewSheet ( destination : SheetDestination ) -> some View {
Group {
switch destination {
case . post ( let content , let replyId , let editId ) :
NavigationStack {
PostingView ( initialString : content , replyId : replyId , editId : editId )
. tint ( Color ( uiColor : UIColor . label ) )
}
2024-07-30 18:43:03 +02:00
case . profEdit :
EditProfileView ( )
2024-02-04 08:43:56 +01:00
case let . mastodonLogin ( logged ) :
AddInstanceView ( logged : logged )
. tint ( Color . accentColor )
case let . safari ( url ) :
SfSafariView ( url : url )
. ignoresSafeArea ( )
case let . shareImage ( image , status ) :
ShareSheet ( image : image , status : status )
2024-02-20 22:31:44 +01:00
case . update :
UpdateView ( )
2024-08-10 02:40:41 +02:00
case let . reportStatus ( status ) :
ReportStatusView ( status : status )
2024-02-04 08:43:56 +01:00
default :
EmptySheetView ( destId : destination . id )
}
}
}
2023-12-29 11:17:37 +01:00
}
2024-01-27 08:56:22 +01:00
2024-02-04 08:43:56 +01:00
// / T h i s v i e w i s v i s i b l e w h e n t h e ` v i e w R e p r e s e n t a t i o n ( d e s t i n a t i o n : S h e e t D e s t i n a t i o n ) ` d o e s n ' t s u p p o r t t h e g i v e n ` S h e e t D e s t i n a t i o n `
2024-01-27 08:56:22 +01:00
private struct EmptySheetView : View {
2024-02-04 08:43:56 +01:00
@ Environment ( \ . dismiss ) private var dismiss
var destId : String = " "
2024-01-28 17:51:50 +01:00
let str : String = . init ( localized : " about.version- \( AppInfo . appVersion ) " )
2024-01-27 08:56:22 +01:00
var body : some View {
ZStack {
2024-02-04 08:43:56 +01:00
Rectangle ( )
. fill ( Color . red . gradient )
2024-01-27 08:56:22 +01:00
. ignoresSafeArea ( )
2024-02-04 08:43:56 +01:00
VStack {
ContentUnavailableView ( String ( " Missing view for \" \( destId . isEmpty ? " [EMPTY_DEST_ID] " : destId ) \" " ) , systemImage : " exclamationmark.triangle.fill " , description : Text ( String ( " Please notify Lumaa as soon as possible! \n \n \( str ) " ) ) )
. foregroundStyle ( . white )
Button {
dismiss ( )
} label : {
Text ( String ( " Dismiss " ) )
}
. buttonStyle ( LargeButton ( filled : true ) )
}
2024-01-27 08:56:22 +01:00
}
}
}