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-01-02 14:23:36 +01:00
public class Navigator : ObservableObject {
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 ?
2023-12-29 11:17:37 +01:00
public var selectedTab : TabDestination = . timeline
2024-02-04 08:43:56 +01:00
public var showTabbar : Bool = true
2023-12-29 11:17:37 +01:00
public func navigate ( to : RouterDestination ) {
path . append ( to )
2024-02-04 08:43:56 +01:00
if path . contains ( where : { $0 = = . settings } ) {
toggleTabbar ( false )
} else {
toggleTabbar ( true )
}
2023-12-29 11:17:37 +01:00
}
2024-01-28 17:51:50 +01:00
public func removeSettingsOfPath ( ) {
self . path = self . path . filter ( { ! RouterDestination . allSettings . contains ( $0 ) } )
}
2024-02-04 08:43:56 +01:00
// / D e f i n e s t h e v i s i b i l i t y o f t h e m a i n t a b b a r i n f r o m ` C o n t e n t V i e w `
// / - P a r a m e t e r b o o l : ` t r u e ` s h o w s t h e t a b b a r a n d ` f a l s e ` h i d e s t h e t a b b a r
public func toggleTabbar ( _ bool : Bool ? = nil ) {
print ( " \( ( bool ? ? ! self . showTabbar ) ? " shown " : " hide " ) the tab bar " )
withAnimation ( . easeInOut ( duration : 0.4 ) ) {
self . showTabbar = bool ? ? ! self . showTabbar
}
}
2023-12-29 11:17:37 +01:00
}
2024-02-04 08:43:56 +01:00
public class UniversalNavigator : Navigator { }
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
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-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 )
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 "
2023-12-29 11:17:37 +01:00
case . mastodonLogin :
return " login "
case . post :
return " post "
2024-01-21 13:08:06 +01:00
case . safari :
return " safari "
2024-01-21 16:34:26 +01:00
case . shareImage :
return " shareImage "
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
2023-12-29 11:17:37 +01:00
case . mastodonLogin :
return false
case . post :
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
2023-12-29 11:17:37 +01:00
}
}
}
public enum RouterDestination : Hashable {
case settings
case privacy
2024-01-04 22:19:35 +01:00
case appearence
2023-12-29 11:17:37 +01:00
case account ( acc : Account )
2024-01-10 17:45:41 +01:00
case post ( status : Status )
2023-12-30 20:59:09 +01:00
case about
2024-02-10 02:22:39 +01:00
case contacts
2024-02-11 14:22:27 +01:00
case timeline ( timeline : TimelineFilter ? )
2023-12-29 11:17:37 +01:00
}
2024-01-28 17:51:50 +01:00
extension RouterDestination {
static let allSettings : [ RouterDestination ] = [ . settings , . privacy , . about , . appearence ]
}
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-01-02 14:23:36 +01:00
SettingsView ( navigator : navigator )
2023-12-29 11:17:37 +01:00
case . privacy :
PrivacyView ( )
2024-01-04 22:19:35 +01:00
case . appearence :
AppearenceView ( )
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-02-11 14:22:27 +01:00
case . timeline ( let timeline ) :
PostsView ( filter : timeline ? ? . home , showHero : false )
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
@ available ( * , deprecated , renamed : " withSheets " , message : " These two cannot support themselves " )
func withOver ( sheetDestination : Binding < SheetDestination ? > ) -> some View {
self
. withCovers ( sheetDestination : sheetDestination )
. withSheets ( sheetDestination : sheetDestination )
}
@ available ( * , deprecated , message : " Causes bugs with sheets to display as covers " )
2023-12-29 11:17:37 +01:00
private func viewRepresentation ( destination : SheetDestination , isCover : Bool ) -> some View {
Group {
if destination . isCover {
switch destination {
case . welcome :
ConnectView ( )
2024-01-27 08:56:22 +01:00
case . shop :
ShopView ( )
2023-12-29 11:17:37 +01:00
default :
2024-01-27 08:56:22 +01:00
EmptySheetView ( destId : destination . id )
2023-12-29 11:17:37 +01:00
}
} else {
switch destination {
2024-01-26 14:10:17 +01:00
case . post ( let content , let replyId , let editId ) :
2024-01-02 14:23:36 +01:00
NavigationStack {
2024-01-26 14:10:17 +01:00
PostingView ( initialString : content , replyId : replyId , editId : editId )
2024-01-02 14:23:36 +01:00
. tint ( Color ( uiColor : UIColor . label ) )
}
2023-12-29 11:17:37 +01:00
case let . mastodonLogin ( logged ) :
AddInstanceView ( logged : logged )
. tint ( Color . accentColor )
2024-01-21 13:08:06 +01:00
case let . safari ( url ) :
SfSafariView ( url : url )
2024-01-26 14:10:17 +01:00
. ignoresSafeArea ( )
case let . shareImage ( image , status ) :
ShareSheet ( image : image , status : status )
2023-12-29 11:17:37 +01:00
default :
2024-01-27 08:56:22 +01:00
EmptySheetView ( destId : destination . id )
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 ( )
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 ) )
}
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 )
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
}
}
}