2021-07-11 20:52:49 +00:00
import Foundation
2022-12-16 08:35:10 +00:00
import Siesta
2021-07-11 20:52:49 +00:00
import SwiftUI
2021-09-25 08:18:22 +00:00
final class NavigationModel : ObservableObject {
2022-11-24 20:36:05 +00:00
static var shared = NavigationModel ( )
var player = PlayerModel . shared
var recents = RecentsModel . shared
var search = SearchModel . shared
2022-08-15 12:49:12 +00:00
2021-08-29 21:36:18 +00:00
enum TabSelection : Hashable {
2022-11-09 13:34:04 +00:00
case home
2022-11-12 23:01:04 +00:00
case documents
2021-10-05 20:20:09 +00:00
case subscriptions
case popular
case trending
case playlists
case channel ( String )
case playlist ( String )
case recentlyOpened ( String )
case nowPlaying
case search
2022-06-26 13:17:18 +00:00
#if os ( tvOS )
case settings
#endif
2021-10-24 21:36:24 +00:00
2022-03-27 18:38:59 +00:00
var stringValue : String {
switch self {
2022-11-09 13:34:04 +00:00
case . home :
2022-03-27 18:38:59 +00:00
return " favorites "
case . subscriptions :
return " subscriptions "
case . popular :
return " popular "
case . trending :
return " trending "
case . playlists :
return " playlists "
case let . channel ( string ) :
return " channel \( string ) "
case let . playlist ( string ) :
return " playlist \( string ) "
case . recentlyOpened :
return " recentlyOpened "
case . search :
return " search "
2022-06-26 13:17:18 +00:00
#if os ( tvOS )
2023-04-22 13:08:33 +00:00
case . settings :
2022-06-26 13:17:18 +00:00
return " settings "
#endif
2022-03-27 18:38:59 +00:00
default :
return " "
}
}
2021-10-24 21:36:24 +00:00
var playlistID : Playlist . ID ? {
if case let . playlist ( id ) = self {
return id
}
return nil
}
2021-08-29 21:36:18 +00:00
}
2023-05-26 21:18:55 +00:00
@ Published var tabSelection : TabSelection ! { didSet {
if oldValue = = tabSelection { multipleTapHandler ( ) }
2023-09-23 19:49:41 +00:00
if tabSelection = = nil , let item = recents . presentedItem {
2023-09-24 09:14:24 +00:00
Delay . by ( 0.2 ) { [ weak self ] in
2023-09-23 19:49:41 +00:00
self ? . tabSelection = . recentlyOpened ( item . tag )
}
}
2023-05-26 21:18:55 +00:00
} }
2021-07-11 20:52:49 +00:00
2021-09-28 18:06:05 +00:00
@ Published var presentingAddToPlaylist = false
@ Published var videoToAddToPlaylist : Video !
2021-08-29 21:36:18 +00:00
@ Published var presentingPlaylistForm = false
@ Published var editedPlaylist : Playlist !
@ Published var presentingUnsubscribeAlert = false
@ Published var channelToUnsubscribe : Channel !
2021-10-22 23:04:03 +00:00
@ Published var presentingChannel = false
@ Published var presentingPlaylist = false
2021-08-31 21:17:50 +00:00
@ Published var sidebarSectionChanged = false
2022-12-21 20:16:47 +00:00
@ Published var presentingPlaybackSettings = false
2022-11-10 17:11:28 +00:00
@ Published var presentingOpenVideos = false
2021-09-25 08:18:22 +00:00
@ Published var presentingSettings = false
2022-12-11 22:15:56 +00:00
@ Published var presentingAccounts = false
2021-10-17 23:06:00 +00:00
@ Published var presentingWelcomeScreen = false
2023-05-25 12:28:29 +00:00
@ Published var presentingHomeSettings = false
2021-09-25 08:18:22 +00:00
2023-04-22 08:56:42 +00:00
@ Published var presentingChannelSheet = false
@ Published var channelPresentedInSheet : Channel !
2022-06-26 11:57:02 +00:00
@ Published var presentingShareSheet = false
@ Published var shareURL : URL ?
2022-06-24 22:48:57 +00:00
@ Published var alert = Alert ( title : Text ( " Error " ) )
2022-06-18 12:39:49 +00:00
@ Published var presentingAlert = false
2022-11-11 17:50:13 +00:00
@ Published var presentingAlertInOpenVideos = false
2022-06-24 22:48:57 +00:00
#if os ( macOS )
@ Published var presentingAlertInVideoPlayer = false
#endif
2022-06-18 12:39:49 +00:00
2022-11-11 17:50:13 +00:00
@ Published var presentingFileImporter = false
2022-11-24 20:36:05 +00:00
func openChannel ( _ channel : Channel , navigationStyle : NavigationStyle ) {
2022-04-16 17:44:07 +00:00
guard channel . id != Video . fixtureChannelID else {
return
}
2022-11-24 20:36:05 +00:00
hideKeyboard ( )
2022-08-19 21:55:02 +00:00
let presentingPlayer = player . presentingPlayer
2022-11-24 20:36:05 +00:00
presentingChannel = false
2022-05-29 18:26:56 +00:00
2021-12-19 17:17:04 +00:00
#if os ( macOS )
2022-01-06 15:35:45 +00:00
Windows . main . open ( )
2021-12-19 17:17:04 +00:00
#endif
2021-12-17 16:34:55 +00:00
2022-07-10 17:51:46 +00:00
let recent = RecentItem ( from : channel )
recents . add ( RecentItem ( from : channel ) )
2023-04-22 08:56:42 +00:00
let navigateToChannel = {
2022-08-19 21:55:02 +00:00
#if os ( iOS )
2023-04-22 08:56:42 +00:00
self . player . hide ( )
2022-08-19 21:55:02 +00:00
#endif
2023-04-22 08:56:42 +00:00
if navigationStyle = = . sidebar {
self . sidebarSectionChanged . toggle ( )
self . tabSelection = . recentlyOpened ( recent . tag )
} else {
2022-08-25 17:09:55 +00:00
withAnimation ( Constants . overlayAnimation ) {
2022-11-24 20:36:05 +00:00
self . presentingChannel = true
2022-08-19 21:55:02 +00:00
}
2022-06-30 08:05:32 +00:00
}
2022-01-06 16:55:56 +00:00
}
2023-04-22 08:56:42 +00:00
#if os ( iOS )
if presentingPlayer {
presentChannelInSheet ( channel )
} else {
navigateToChannel ( )
}
2023-05-22 21:01:54 +00:00
#elseif os ( tvOS )
Delay . by ( 0.01 ) {
navigateToChannel ( )
}
2023-04-22 08:56:42 +00:00
#else
navigateToChannel ( )
#endif
2022-01-06 16:55:56 +00:00
}
2022-11-24 20:36:05 +00:00
func openChannelPlaylist ( _ playlist : ChannelPlaylist , navigationStyle : NavigationStyle ) {
presentingChannel = false
presentingPlaylist = false
2022-05-29 19:09:57 +00:00
2022-01-06 16:55:56 +00:00
let recent = RecentItem ( from : playlist )
#if os ( macOS )
Windows . main . open ( )
#else
player . hide ( )
#endif
2022-11-24 20:36:05 +00:00
hideKeyboard ( )
2022-11-27 10:42:16 +00:00
presentingChannel = false
2022-08-19 21:55:02 +00:00
let presentingPlayer = player . presentingPlayer
player . hide ( )
2022-08-09 19:14:05 +00:00
2022-11-24 20:36:05 +00:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.2 ) { [ weak self ] in
guard let self else { return }
self . recents . add ( recent )
2022-06-30 08:05:32 +00:00
if navigationStyle = = . sidebar {
2022-11-24 20:36:05 +00:00
self . sidebarSectionChanged . toggle ( )
self . tabSelection = . recentlyOpened ( recent . tag )
2022-06-30 08:05:32 +00:00
} else {
2022-08-19 21:55:02 +00:00
var delay = 0.0
#if os ( iOS )
if presentingPlayer { delay = 1.0 }
#endif
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + delay ) {
2022-08-25 17:09:55 +00:00
withAnimation ( Constants . overlayAnimation ) {
2022-11-24 20:36:05 +00:00
self . presentingPlaylist = true
2022-08-19 21:55:02 +00:00
}
2022-07-09 00:21:04 +00:00
}
2022-06-30 08:05:32 +00:00
}
2022-01-06 16:55:56 +00:00
}
2022-06-24 22:48:57 +00:00
}
2022-11-24 20:36:05 +00:00
func openSearchQuery ( _ searchQuery : String ? ) {
presentingChannel = false
presentingPlaylist = false
tabSelection = . search
2022-06-24 22:48:57 +00:00
2022-11-24 20:36:05 +00:00
hideKeyboard ( )
2022-08-09 19:14:05 +00:00
2022-08-19 21:55:02 +00:00
let presentingPlayer = player . presentingPlayer
player . hide ( )
2022-09-28 14:27:01 +00:00
if let searchQuery {
2022-06-24 22:48:57 +00:00
let recent = RecentItem ( from : searchQuery )
recents . add ( recent )
2022-01-06 16:55:56 +00:00
2022-08-19 21:55:02 +00:00
var delay = 0.0
#if os ( iOS )
if presentingPlayer { delay = 1.0 }
#endif
2022-11-24 20:36:05 +00:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + delay ) { [ weak self ] in
guard let self else { return }
self . search . queryText = searchQuery
self . search . changeQuery { query in query . query = searchQuery }
2021-12-17 16:34:55 +00:00
}
}
2022-06-24 22:48:57 +00:00
#if os ( macOS )
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.5 ) {
Windows . main . focus ( )
}
#endif
2021-12-17 16:34:55 +00:00
}
2021-09-28 23:01:49 +00:00
var tabSelectionBinding : Binding < TabSelection > {
Binding < TabSelection > (
2021-07-11 20:52:49 +00:00
get : {
2021-12-19 23:36:12 +00:00
self . tabSelection ? ? . search
2021-07-11 20:52:49 +00:00
} ,
2021-08-31 21:17:50 +00:00
set : { newValue in
2021-09-28 23:01:49 +00:00
self . tabSelection = newValue
2021-07-11 20:52:49 +00:00
}
)
}
2021-08-29 21:36:18 +00:00
2021-09-28 18:06:05 +00:00
func presentAddToPlaylist ( _ video : Video ) {
videoToAddToPlaylist = video
presentingAddToPlaylist = true
}
2021-08-29 21:36:18 +00:00
func presentEditPlaylistForm ( _ playlist : Playlist ? ) {
editedPlaylist = playlist
presentingPlaylistForm = editedPlaylist != nil
}
func presentNewPlaylistForm ( ) {
editedPlaylist = nil
presentingPlaylistForm = true
}
2022-12-11 15:15:42 +00:00
func presentUnsubscribeAlert ( _ channel : Channel , subscriptions : SubscribedChannelsModel ) {
2021-08-29 21:36:18 +00:00
channelToUnsubscribe = channel
2022-06-24 23:21:05 +00:00
alert = Alert (
title : Text (
" Are you sure you want to unsubscribe from \( channelToUnsubscribe . name ) ? "
) ,
primaryButton : . destructive ( Text ( " Unsubscribe " ) ) { [ weak self ] in
if let id = self ? . channelToUnsubscribe . id {
subscriptions . unsubscribe ( id )
}
} ,
secondaryButton : . cancel ( )
)
presentingAlert = true
2021-08-29 21:36:18 +00:00
}
2022-03-26 14:22:29 +00:00
2022-12-11 15:00:20 +00:00
func hideViewsAboveBrowser ( ) {
player . hide ( )
presentingChannel = false
presentingPlaylist = false
presentingOpenVideos = false
}
2022-03-26 14:22:29 +00:00
func hideKeyboard ( ) {
#if os ( iOS )
UIApplication . shared . sendAction ( #selector ( UIResponder . resignFirstResponder ) , to : nil , from : nil , for : nil )
#endif
}
2022-06-18 12:39:49 +00:00
2022-07-01 21:28:32 +00:00
func presentAlert ( title : String , message : String ? = nil ) {
let message = message . isNil ? nil : Text ( message ! )
alert = Alert ( title : Text ( title ) , message : message )
2022-06-18 12:39:49 +00:00
presentingAlert = true
}
2022-06-26 11:57:02 +00:00
2022-12-16 08:35:10 +00:00
func presentRequestErrorAlert ( _ error : RequestError ) {
let errorDescription = String ( format : " Verify you have stable connection with the server you are using (%@) " , AccountsModel . shared . current . instance . longDescription )
presentAlert ( title : " Connection Error " , message : " \( error . userMessage ) \n \n \( errorDescription ) " )
}
2022-08-21 15:39:06 +00:00
func presentAlert ( _ alert : Alert ) {
self . alert = alert
presentingAlert = true
}
2022-06-26 11:57:02 +00:00
func presentShareSheet ( _ url : URL ) {
shareURL = url
presentingShareSheet = true
}
2023-04-22 08:56:42 +00:00
func presentChannelInSheet ( _ channel : Channel ) {
channelPresentedInSheet = channel
presentingChannelSheet = true
}
2023-05-26 21:18:55 +00:00
func multipleTapHandler ( ) {
switch tabSelection {
case . search :
self . search . focused = true
default :
print ( " not implemented " )
}
}
2021-07-11 20:52:49 +00:00
}
2021-08-29 21:36:18 +00:00
2021-09-25 08:18:22 +00:00
typealias TabSelection = NavigationModel . TabSelection