More TabView cleanup

Bump to iOS 18 only + remove custom sidebar
This commit is contained in:
Thomas Ricouard 2024-07-09 10:46:49 +02:00
parent 76a6462867
commit e051437fcb
28 changed files with 174 additions and 568 deletions

View file

@ -36,7 +36,7 @@
9F2A542A296AF557009B2D7C /* NotificationServiceSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5429296AF557009B2D7C /* NotificationServiceSupport.swift */; }; 9F2A542A296AF557009B2D7C /* NotificationServiceSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5429296AF557009B2D7C /* NotificationServiceSupport.swift */; };
9F2A542C296B1177009B2D7C /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; }; 9F2A542C296B1177009B2D7C /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; };
9F2A542E296B1CC0009B2D7C /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; }; 9F2A542E296B1CC0009B2D7C /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; };
9F2B92F6295AE04800DE16D0 /* Tabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92F5295AE04800DE16D0 /* Tabs.swift */; }; 9F2B92F6295AE04800DE16D0 /* AppTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92F5295AE04800DE16D0 /* AppTab.swift */; };
9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */; }; 9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */; };
9F2B92FC295DA94500DE16D0 /* InstanceInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92FB295DA94500DE16D0 /* InstanceInfoView.swift */; }; 9F2B92FC295DA94500DE16D0 /* InstanceInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B92FB295DA94500DE16D0 /* InstanceInfoView.swift */; };
9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4629506F6600B3281A /* NotificationTab.swift */; }; 9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4629506F6600B3281A /* NotificationTab.swift */; };
@ -102,14 +102,12 @@
9FAD85A0297456A100496AB1 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD859F297456A100496AB1 /* Models */; }; 9FAD85A0297456A100496AB1 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD859F297456A100496AB1 /* Models */; };
9FAD85A2297456A400496AB1 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD85A1297456A400496AB1 /* Env */; }; 9FAD85A2297456A400496AB1 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD85A1297456A400496AB1 /* Env */; };
9FAD85A4297456A800496AB1 /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD85A3297456A800496AB1 /* DesignSystem */; }; 9FAD85A4297456A800496AB1 /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAD85A3297456A800496AB1 /* DesignSystem */; };
9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD85CE2975B68900496AB1 /* SideBarView.swift */; };
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAE4ACA293783B000772766 /* SettingsTab.swift */; }; 9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAE4ACA293783B000772766 /* SettingsTab.swift */; };
9FAE4ACE29379A5A00772766 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAE4ACD29379A5A00772766 /* KeychainSwift */; }; 9FAE4ACE29379A5A00772766 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9FAE4ACD29379A5A00772766 /* KeychainSwift */; };
9FB143D12983104700A27BB1 /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; }; 9FB143D12983104700A27BB1 /* glass.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542B296B1177009B2D7C /* glass.caf */; };
9FB143D22983104A00A27BB1 /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; }; 9FB143D22983104A00A27BB1 /* glass.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9F2A542D296B1CC0009B2D7C /* glass.wav */; };
9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */; }; 9FB183222AE9268800BBB692 /* IceCubesApp+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */; };
9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */; }; 9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */; };
9FBA1D352B4E9B7E00ADB568 /* SidebarEntriesSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBA1D342B4E9B7E00ADB568 /* SidebarEntriesSettingsView.swift */; };
9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; }; 9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; };
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; }; 9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; };
9FC14EF22B494D180006CEE1 /* TagsGroupSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */; }; 9FC14EF22B494D180006CEE1 /* TagsGroupSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */; };
@ -231,7 +229,7 @@
9F2A5429296AF557009B2D7C /* NotificationServiceSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceSupport.swift; sourceTree = "<group>"; }; 9F2A5429296AF557009B2D7C /* NotificationServiceSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceSupport.swift; sourceTree = "<group>"; };
9F2A542B296B1177009B2D7C /* glass.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = glass.caf; sourceTree = "<group>"; }; 9F2A542B296B1177009B2D7C /* glass.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = glass.caf; sourceTree = "<group>"; };
9F2A542D296B1CC0009B2D7C /* glass.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = glass.wav; sourceTree = "<group>"; }; 9F2A542D296B1CC0009B2D7C /* glass.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = glass.wav; sourceTree = "<group>"; };
9F2B92F5295AE04800DE16D0 /* Tabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tabs.swift; sourceTree = "<group>"; }; 9F2B92F5295AE04800DE16D0 /* AppTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTab.swift; sourceTree = "<group>"; };
9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountsView.swift; sourceTree = "<group>"; }; 9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountsView.swift; sourceTree = "<group>"; };
9F2B92FB295DA94500DE16D0 /* InstanceInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceInfoView.swift; sourceTree = "<group>"; }; 9F2B92FB295DA94500DE16D0 /* InstanceInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceInfoView.swift; sourceTree = "<group>"; };
9F35DB45294FA04C00B3281A /* DesignSystem */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DesignSystem; path = Packages/DesignSystem; sourceTree = "<group>"; }; 9F35DB45294FA04C00B3281A /* DesignSystem */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DesignSystem; path = Packages/DesignSystem; sourceTree = "<group>"; };
@ -286,12 +284,10 @@
9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; }; 9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
9FAD858F29743F7400496AB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 9FAD858F29743F7400496AB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9FAD859629743F7E00496AB1 /* IceCubesShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IceCubesShareExtension.entitlements; sourceTree = "<group>"; }; 9FAD859629743F7E00496AB1 /* IceCubesShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IceCubesShareExtension.entitlements; sourceTree = "<group>"; };
9FAD85CE2975B68900496AB1 /* SideBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideBarView.swift; sourceTree = "<group>"; };
9FAE4AC8293774FF00772766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 9FAE4AC8293774FF00772766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
9FAE4ACA293783B000772766 /* SettingsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTab.swift; sourceTree = "<group>"; }; 9FAE4ACA293783B000772766 /* SettingsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTab.swift; sourceTree = "<group>"; };
9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Menu.swift"; sourceTree = "<group>"; }; 9FB183212AE9268800BBB692 /* IceCubesApp+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Menu.swift"; sourceTree = "<group>"; };
9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Scene.swift"; sourceTree = "<group>"; }; 9FB183282AE9449100BBB692 /* IceCubesApp+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IceCubesApp+Scene.swift"; sourceTree = "<group>"; };
9FBA1D342B4E9B7E00ADB568 /* SidebarEntriesSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarEntriesSettingsView.swift; sourceTree = "<group>"; };
9FBFE639292A715500C250E9 /* Ice Cubes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ice Cubes.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9FBFE639292A715500C250E9 /* Ice Cubes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ice Cubes.app"; sourceTree = BUILT_PRODUCTS_DIR; };
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; }; 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; };
9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsGroupSettingView.swift; sourceTree = "<group>"; }; 9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsGroupSettingView.swift; sourceTree = "<group>"; };
@ -460,7 +456,6 @@
9FAE4AC9293783A200772766 /* Tabs */, 9FAE4AC9293783A200772766 /* Tabs */,
9F398AA52935FE8A00A889F2 /* AppRegistry.swift */, 9F398AA52935FE8A00A889F2 /* AppRegistry.swift */,
639CDF9B296AC82F00C35E58 /* SafariRouter.swift */, 639CDF9B296AC82F00C35E58 /* SafariRouter.swift */,
9FAD85CE2975B68900496AB1 /* SideBarView.swift */,
); );
path = App; path = App;
sourceTree = "<group>"; sourceTree = "<group>";
@ -565,7 +560,7 @@
9F35DB4629506F6600B3281A /* NotificationTab.swift */, 9F35DB4629506F6600B3281A /* NotificationTab.swift */,
9F35DB4B2952005C00B3281A /* MessagesTab.swift */, 9F35DB4B2952005C00B3281A /* MessagesTab.swift */,
9F55C68C2955968700F94077 /* ExploreTab.swift */, 9F55C68C2955968700F94077 /* ExploreTab.swift */,
9F2B92F5295AE04800DE16D0 /* Tabs.swift */, 9F2B92F5295AE04800DE16D0 /* AppTab.swift */,
9F4A48182976B21900A1A038 /* ProfileTab.swift */, 9F4A48182976B21900A1A038 /* ProfileTab.swift */,
9F15D5FF2B3D6A850008C220 /* NavigationTab.swift */, 9F15D5FF2B3D6A850008C220 /* NavigationTab.swift */,
9F15D6032B3DC2180008C220 /* NavigationSheet.swift */, 9F15D6032B3DC2180008C220 /* NavigationSheet.swift */,
@ -672,7 +667,6 @@
9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */, 9FC14EF12B494D180006CEE1 /* TagsGroupSettingView.swift */,
9FC14EF32B494D940006CEE1 /* RemoteTimelinesSettingView.swift */, 9FC14EF32B494D940006CEE1 /* RemoteTimelinesSettingView.swift */,
9FC14EF52B494DFF0006CEE1 /* RecenTagsSettingView.swift */, 9FC14EF52B494DFF0006CEE1 /* RecenTagsSettingView.swift */,
9FBA1D342B4E9B7E00ADB568 /* SidebarEntriesSettingsView.swift */,
); );
path = Settings; path = Settings;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1071,7 +1065,6 @@
9F37BDE12BE38646007F28AD /* PostImageIntent.swift in Sources */, 9F37BDE12BE38646007F28AD /* PostImageIntent.swift in Sources */,
9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */, 9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */,
9F7788C02BE63935004E6BEF /* InlinePostIntent.swift in Sources */, 9F7788C02BE63935004E6BEF /* InlinePostIntent.swift in Sources */,
9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */,
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */, 9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
9FC14EF42B494D940006CEE1 /* RemoteTimelinesSettingView.swift in Sources */, 9FC14EF42B494D940006CEE1 /* RemoteTimelinesSettingView.swift in Sources */,
9FC14EF22B494D180006CEE1 /* TagsGroupSettingView.swift in Sources */, 9FC14EF22B494D180006CEE1 /* TagsGroupSettingView.swift in Sources */,
@ -1079,7 +1072,7 @@
9F7335F92968576500AFF0BA /* DisplaySettingsView.swift in Sources */, 9F7335F92968576500AFF0BA /* DisplaySettingsView.swift in Sources */,
9F2A540729699698009B2D7C /* SupportAppView.swift in Sources */, 9F2A540729699698009B2D7C /* SupportAppView.swift in Sources */,
9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */, 9FB183292AE9449100BBB692 /* IceCubesApp+Scene.swift in Sources */,
9F2B92F6295AE04800DE16D0 /* Tabs.swift in Sources */, 9F2B92F6295AE04800DE16D0 /* AppTab.swift in Sources */,
FA31A9AB2A66BF7C00D5F662 /* EditTagGroupView.swift in Sources */, FA31A9AB2A66BF7C00D5F662 /* EditTagGroupView.swift in Sources */,
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */, 9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */,
9F398AA62935FE8A00A889F2 /* AppRegistry.swift in Sources */, 9F398AA62935FE8A00A889F2 /* AppRegistry.swift in Sources */,
@ -1099,7 +1092,6 @@
9F6028562B3F36AE00476078 /* AppView.swift in Sources */, 9F6028562B3F36AE00476078 /* AppView.swift in Sources */,
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */, 9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */,
9F1E8B47298EBCBB00609F80 /* HapticSettingsView.swift in Sources */, 9F1E8B47298EBCBB00609F80 /* HapticSettingsView.swift in Sources */,
9FBA1D352B4E9B7E00ADB568 /* SidebarEntriesSettingsView.swift in Sources */,
9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */, 9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */,
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */, 9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */,
); );
@ -1187,7 +1179,7 @@
INFOPLIST_FILE = IceCubesNotifications/Info.plist; INFOPLIST_FILE = IceCubesNotifications/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesNotifications; INFOPLIST_KEY_CFBundleDisplayName = IceCubesNotifications;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1222,7 +1214,7 @@
INFOPLIST_FILE = IceCubesNotifications/Info.plist; INFOPLIST_FILE = IceCubesNotifications/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesNotifications; INFOPLIST_KEY_CFBundleDisplayName = IceCubesNotifications;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1261,7 +1253,7 @@
INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist; INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension; INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.4; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1297,7 +1289,7 @@
INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist; INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension; INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.4; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1330,7 +1322,7 @@
INFOPLIST_FILE = IceCubesShareExtension/Info.plist; INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes"; INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes";
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1364,7 +1356,7 @@
INFOPLIST_FILE = IceCubesShareExtension/Info.plist; INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes"; INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes";
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1548,7 +1540,7 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
@ -1573,7 +1565,7 @@
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES; _EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = NO;
}; };
name = Debug; name = Debug;
}; };
@ -1615,7 +1607,7 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
@ -1640,7 +1632,7 @@
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES; _EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = NO;
}; };
name = Release; name = Release;
}; };
@ -1659,7 +1651,7 @@
INFOPLIST_FILE = IceCubesActionExtension/Info.plist; INFOPLIST_FILE = IceCubesActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube"; INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube";
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1694,7 +1686,7 @@
INFOPLIST_FILE = IceCubesActionExtension/Info.plist; INFOPLIST_FILE = IceCubesActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube"; INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube";
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0; IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View file

@ -133,7 +133,7 @@ extension View {
StatusEditHistoryView(statusId: status) StatusEditHistoryView(statusId: status)
.withEnvironments() .withEnvironments()
case .settings: case .settings:
SettingsTabs(popToRootTab: .constant(.settings), isModal: true) SettingsTabs(isModal: true)
.withEnvironments() .withEnvironments()
.preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light) .preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light)
case .accountPushNotficationsSettings: case .accountPushNotficationsSettings:

View file

@ -21,12 +21,12 @@ struct AppView: View {
@Environment(\.openWindow) var openWindow @Environment(\.openWindow) var openWindow
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Binding var selectedTab: Tab @Binding var selectedTab: AppTab
@Binding var appRouterPath: RouterPath @Binding var appRouterPath: RouterPath
@State var popToRootTab: Tab = .other
@State var iosTabs = iOSTabs.shared @State var iosTabs = iOSTabs.shared
@State var sidebarTabs = SidebarTabs.shared @AppStorage("SidebarTabsCustomization")
private var sidebarTabsCustomization: TabViewCustomization
var body: some View { var body: some View {
#if os(visionOS) #if os(visionOS)
@ -40,16 +40,16 @@ struct AppView: View {
#endif #endif
} }
var availableTabs: [Tab] { var availableTabs: [AppTab] {
guard appAccountsManager.currentClient.isAuth else { guard appAccountsManager.currentClient.isAuth else {
return Tab.loggedOutTab() return AppTab.loggedOutTab()
} }
if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact { if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact {
return iosTabs.tabs return iosTabs.tabs
} else if UIDevice.current.userInterfaceIdiom == .vision { } else if UIDevice.current.userInterfaceIdiom == .vision {
return Tab.visionOSTab() return AppTab.visionOSTab()
} }
return sidebarTabs.tabs.map { $0.tab } return AppTab.sideBarTab()
} }
var tabBarView: some View { var tabBarView: some View {
@ -64,39 +64,31 @@ struct AppView: View {
#endif #endif
return return
} }
if newTab == selectedTab {
/// Stupid hack to trigger onChange binding in tab views.
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = selectedTab
}
}
HapticManager.shared.fireHaptic(.tabSelection) HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection) SoundEffectManager.shared.playSound(.tabSelection)
selectedTab = newTab selectedTab = newTab
})) { })) {
ForEach(availableTabs) { tab in ForEach(availableTabs) { tab in
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab) Tab(value: tab) {
.tabItem { tab.makeContentView(selectedTab: $selectedTab)
if userPreferences.showiPhoneTabLabel { .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .tabBar)
tab.label } label: {
.environment(\.symbolVariants, tab == selectedTab ? .fill : .none) if userPreferences.showiPhoneTabLabel {
} else { tab.label
Image(systemName: tab.iconName) .environment(\.symbolVariants, tab == selectedTab ? .fill : .none)
} } else {
Image(systemName: tab.iconName)
} }
.tag(tab) }
.badge(badgeFor(tab: tab)) .badge(badgeFor(tab: tab))
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .tabBar)
} }
} }
.id(appAccountsManager.currentClient.id) .id(appAccountsManager.currentClient.id)
.withSheetDestinations(sheetDestinations: $appRouterPath.presentedSheet) .withSheetDestinations(sheetDestinations: $appRouterPath.presentedSheet)
} }
private func badgeFor(tab: Tab) -> Int { private func badgeFor(tab: AppTab) -> Int {
if tab == .notifications, selectedTab != tab, if tab == .notifications, selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken let token = appAccountsManager.currentAccount.oauthToken
{ {
@ -107,42 +99,38 @@ struct AppView: View {
#if !os(visionOS) #if !os(visionOS)
var sidebarView: some View { var sidebarView: some View {
SideBarView(selectedTab: $selectedTab, HStack(spacing: 0) {
popToRootTab: $popToRootTab, TabView(selection: $selectedTab) {
tabs: availableTabs) ForEach(availableTabs) { tab in
{ Tab(value: tab, role: tab == .explore ? .search : nil) {
HStack(spacing: 0) {
TabView(selection: $selectedTab) {
ForEach(availableTabs) { tab in
tab tab
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab) .makeContentView(selectedTab: $selectedTab)
.tabItem { } label: {
tab.label tab.label
}
.tag(tab)
} }
} .customizationID(tab.iconName)
.introspect(.tabView, on: .iOS(.v17, .v18)) { (tabview: UITabBarController) in .badge(badgeFor(tab: tab))
tabview.tabBar.isHidden = horizontalSizeClass == .regular
tabview.customizableViewControllers = []
tabview.moreNavigationController.isNavigationBarHidden = true
}
if horizontalSizeClass == .regular,
appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
} }
} }
.tabViewStyle(.sidebarAdaptable)
.tabViewCustomization($sidebarTabsCustomization)
.introspect(.tabView, on: .iOS(.v17, .v18)) { (tabview: UITabBarController) in
tabview.customizableViewControllers = []
tabview.moreNavigationController.isNavigationBarHidden = true
}
if horizontalSizeClass == .regular,
appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
}
} }
.environment(appRouterPath)
} }
#endif #endif
var notificationsSecondaryColumn: some View { var notificationsSecondaryColumn: some View {
NotificationsTab(selectedTab: .constant(.notifications), NotificationsTab(selectedTab: .constant(.notifications), lockedType: nil)
popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true) .environment(\.isSecondaryColumn, true)
.frame(maxWidth: .secondaryColumnWidth) .frame(maxWidth: .secondaryColumnWidth)
.id(appAccountsManager.currentAccount.id) .id(appAccountsManager.currentAccount.id)

View file

@ -28,7 +28,7 @@ struct IceCubesApp: App {
@State var quickLook = QuickLook.shared @State var quickLook = QuickLook.shared
@State var theme = Theme.shared @State var theme = Theme.shared
@State var selectedTab: Tab = .timeline @State var selectedTab: AppTab = .timeline
@State var appRouterPath = RouterPath() @State var appRouterPath = RouterPath()
@State var isSupporter: Bool = false @State var isSupporter: Bool = false

View file

@ -1,245 +0,0 @@
import Account
import AppAccount
import DesignSystem
import Env
import Models
import SwiftUI
import SwiftUIIntrospect
@MainActor
struct SideBarView<Content: View>: View {
@Environment(\.openWindow) private var openWindow
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(AppAccountsManager.self) private var appAccounts
@Environment(CurrentAccount.self) private var currentAccount
@Environment(Theme.self) private var theme
@Environment(StreamWatcher.self) private var watcher
@Environment(UserPreferences.self) private var userPreferences
@Environment(RouterPath.self) private var routerPath
@Binding var selectedTab: Tab
@Binding var popToRootTab: Tab
var tabs: [Tab]
@ViewBuilder var content: () -> Content
@State private var sidebarTabs = SidebarTabs.shared
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications, selectedTab != tab,
let token = appAccounts.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + (userPreferences.notificationsCount[token] ?? 0)
}
return 0
}
private func makeIconForTab(tab: Tab) -> some View {
HStack {
ZStack(alignment: .topTrailing) {
SideBarIcon(systemIconName: tab.iconName,
isSelected: tab == selectedTab)
let badge = badgeFor(tab: tab)
if badge > 0 {
makeBadgeView(count: badge)
}
}
if userPreferences.isSidebarExpanded {
Text(tab.title)
.font(.headline)
.foregroundColor(tab == selectedTab ? theme.tintColor : theme.labelColor)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.frame(width: (userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth) - 24, height: 50)
.background(tab == selectedTab ? theme.secondaryBackgroundColor : .clear,
in: RoundedRectangle(cornerRadius: 8))
}
private func makeBadgeView(count: Int) -> some View {
ZStack {
Circle()
.fill(.red)
Text(count > 99 ? "99+" : String(count))
.foregroundColor(.white)
.font(.caption2)
}
.frame(width: 24, height: 24)
.offset(x: 14, y: -14)
}
private var postButton: some View {
Button {
#if targetEnvironment(macCatalyst) || os(visionOS)
openWindow(value: WindowDestinationEditor.newStatusEditor(visibility: userPreferences.postVisibility))
#else
routerPath.presentedSheet = .newStatusEditor(visibility: userPreferences.postVisibility)
#endif
} label: {
Image(systemName: "square.and.pencil")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 30)
.offset(x: 2, y: -2)
}
.buttonStyle(.borderedProminent)
.help(Tab.post.title)
}
private func makeAccountButton(account: AppAccount, showBadge: Bool) -> some View {
Button {
if account.id == appAccounts.currentAccount.id {
selectedTab = .profile
SoundEffectManager.shared.playSound(.tabSelection)
} else {
var transation = Transaction()
transation.disablesAnimations = true
withTransaction(transation) {
appAccounts.currentAccount = account
}
}
} label: {
ZStack(alignment: .topTrailing) {
if userPreferences.isSidebarExpanded {
AppAccountView(viewModel: .init(appAccount: account,
isCompact: false,
isInSettings: false),
isParentPresented: .constant(false))
} else {
AppAccountView(viewModel: .init(appAccount: account,
isCompact: true,
isInSettings: false),
isParentPresented: .constant(false))
}
if !userPreferences.isSidebarExpanded,
showBadge,
let token = account.oauthToken,
let notificationsCount = userPreferences.notificationsCount[token],
notificationsCount > 0
{
makeBadgeView(count: notificationsCount)
}
}
.padding(.leading, userPreferences.isSidebarExpanded ? 16 : 0)
}
.help(accountButtonTitle(accountName: account.accountName))
.frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth, height: 50)
.padding(.vertical, 8)
.background(selectedTab == .profile && account.id == appAccounts.currentAccount.id ?
theme.secondaryBackgroundColor : .clear)
}
private func accountButtonTitle(accountName: String?) -> LocalizedStringKey {
if let accountName {
"tab.profile-account-\(accountName)"
} else {
Tab.profile.title
}
}
private var tabsView: some View {
ForEach(tabs) { tab in
if tab != .profile && sidebarTabs.isEnabled(tab) {
Button {
// ensure keyboard is always dismissed when selecting a tab
hideKeyboard()
if tab == selectedTab {
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = tab
}
}
selectedTab = tab
SoundEffectManager.shared.playSound(.tabSelection)
if tab == .notifications {
if let token = appAccounts.currentAccount.oauthToken {
userPreferences.notificationsCount[token] = 0
}
watcher.unreadNotificationsCount = 0
}
} label: {
makeIconForTab(tab: tab)
}
.help(tab.title)
}
}
}
var body: some View {
@Bindable var routerPath = routerPath
HStack(spacing: 0) {
if horizontalSizeClass == .regular {
ScrollView {
VStack(alignment: .center) {
if appAccounts.availableAccounts.isEmpty {
tabsView
} else {
ForEach(appAccounts.availableAccounts) { account in
makeAccountButton(account: account,
showBadge: account.id != appAccounts.currentAccount.id)
if account.id == appAccounts.currentAccount.id {
tabsView
}
}
}
}
}
.frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth)
.scrollContentBackground(.hidden)
.background(.thinMaterial)
.safeAreaInset(edge: .bottom, content: {
HStack(spacing: 16) {
postButton
.padding(.vertical, 24)
.padding(.leading, userPreferences.isSidebarExpanded ? 18 : 0)
if userPreferences.isSidebarExpanded {
Text("menu.new-post")
.font(.subheadline)
.foregroundColor(theme.labelColor)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth)
.background(.thinMaterial)
})
Divider().edgesIgnoringSafeArea(.all)
}
content()
}
.background(.thinMaterial)
.edgesIgnoringSafeArea(.bottom)
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
}
}
private struct SideBarIcon: View {
@Environment(Theme.self) private var theme
let systemIconName: String
let isSelected: Bool
@State private var isHovered: Bool = false
var body: some View {
Image(systemName: systemIconName)
.font(.title2)
.fontWeight(.medium)
.foregroundColor(isSelected ? theme.tintColor : theme.labelColor)
.symbolVariant(isSelected ? .fill : .none)
.scaleEffect(isHovered ? 0.8 : 1.0)
.onHover { isHovered in
withAnimation(.interpolatingSpring(stiffness: 300, damping: 15)) {
self.isHovered = isHovered
}
}
.frame(width: 50, height: 40)
}
}
extension View {
@MainActor func hideKeyboard() {
let resign = #selector(UIResponder.resignFirstResponder)
UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
}
}

View file

@ -7,8 +7,8 @@ import StatusKit
import SwiftUI import SwiftUI
@MainActor @MainActor
enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { enum AppTab: Int, Identifiable, Hashable, CaseIterable, Codable {
case timeline, notifications, mentions, explore, messages, settings, other case timeline, notifications, mentions, explore, messages, settings
case trending, federated, local case trending, federated, local
case profile case profile
case bookmarks case bookmarks
@ -22,37 +22,43 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
rawValue rawValue
} }
static func loggedOutTab() -> [Tab] { static func loggedOutTab() -> [AppTab] {
[.timeline, .settings] [.timeline, .settings]
} }
static func visionOSTab() -> [Tab] { static func visionOSTab() -> [AppTab] {
[.profile, .timeline, .notifications, .mentions, .explore, .post, .settings] [.profile, .timeline, .notifications, .mentions, .explore, .post, .settings]
} }
static func sideBarTab() -> [AppTab] {
[.timeline, .trending, .federated, .local, .notifications,
.mentions, .mentions, .explore, .bookmarks, .favorites,
.followedTags, .links, .lists, .settings, .profile]
}
@ViewBuilder @ViewBuilder
func makeContentView(selectedTab: Binding<Tab>, popToRootTab: Binding<Tab>) -> some View { func makeContentView(selectedTab: Binding<AppTab>) -> some View {
switch self { switch self {
case .timeline: case .timeline:
TimelineTab(popToRootTab: popToRootTab) TimelineTab()
case .trending: case .trending:
TimelineTab(popToRootTab: popToRootTab, timeline: .trending) TimelineTab(timeline: .trending)
case .local: case .local:
TimelineTab(popToRootTab: popToRootTab, timeline: .local) TimelineTab(timeline: .local)
case .federated: case .federated:
TimelineTab(popToRootTab: popToRootTab, timeline: .federated) TimelineTab(timeline: .federated)
case .notifications: case .notifications:
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: nil) NotificationsTab(selectedTab: selectedTab, lockedType: nil)
case .mentions: case .mentions:
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: .mention) NotificationsTab(selectedTab: selectedTab, lockedType: .mention)
case .explore: case .explore:
ExploreTab(popToRootTab: popToRootTab) ExploreTab()
case .messages: case .messages:
MessagesTab(popToRootTab: popToRootTab) MessagesTab()
case .settings: case .settings:
SettingsTabs(popToRootTab: popToRootTab, isModal: false) SettingsTabs(isModal: false)
case .profile: case .profile:
ProfileTab(popToRootTab: popToRootTab) ProfileTab()
case .bookmarks: case .bookmarks:
NavigationTab { NavigationTab {
AccountStatusesListView(mode: .bookmarks) AccountStatusesListView(mode: .bookmarks)
@ -73,16 +79,12 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
NavigationTab { TrendingLinksListView(cards: []) } NavigationTab { TrendingLinksListView(cards: []) }
case .post: case .post:
VStack {} VStack {}
case .other:
EmptyView()
} }
} }
@ViewBuilder @ViewBuilder
var label: some View { var label: some View {
if self != .other { Label(title, systemImage: iconName)
Label(title, systemImage: iconName)
}
} }
var title: LocalizedStringKey { var title: LocalizedStringKey {
@ -119,8 +121,6 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
"timeline.filter.lists" "timeline.filter.lists"
case .links: case .links:
"explore.section.trending.links" "explore.section.trending.links"
case .other:
""
} }
} }
@ -158,59 +158,10 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
"list.bullet" "list.bullet"
case .links: case .links:
"newspaper" "newspaper"
case .other:
""
} }
} }
} }
@MainActor
@Observable
class SidebarTabs {
struct SidedebarTab: Hashable, Codable {
let tab: Tab
var enabled: Bool
}
class Storage {
@AppStorage("sidebar_tabs") var tabs: [SidedebarTab] = [
.init(tab: .timeline, enabled: true),
.init(tab: .trending, enabled: true),
.init(tab: .federated, enabled: true),
.init(tab: .local, enabled: true),
.init(tab: .notifications, enabled: true),
.init(tab: .mentions, enabled: true),
.init(tab: .messages, enabled: true),
.init(tab: .explore, enabled: true),
.init(tab: .bookmarks, enabled: true),
.init(tab: .favorites, enabled: true),
.init(tab: .followedTags, enabled: true),
.init(tab: .lists, enabled: true),
.init(tab: .links, enabled: true),
.init(tab: .settings, enabled: true),
.init(tab: .profile, enabled: true),
]
}
private let storage = Storage()
public static let shared = SidebarTabs()
var tabs: [SidedebarTab] {
didSet {
storage.tabs = tabs
}
}
func isEnabled(_ tab: Tab) -> Bool {
tabs.first(where: { $0.tab.id == tab.id })?.enabled == true
}
private init() {
tabs = storage.tabs
}
}
@MainActor @MainActor
@Observable @Observable
class iOSTabs { class iOSTabs {
@ -219,45 +170,45 @@ class iOSTabs {
} }
class Storage { class Storage {
@AppStorage(TabEntries.first.rawValue) var firstTab = Tab.timeline @AppStorage(TabEntries.first.rawValue) var firstTab = AppTab.timeline
@AppStorage(TabEntries.second.rawValue) var secondTab = Tab.notifications @AppStorage(TabEntries.second.rawValue) var secondTab = AppTab.notifications
@AppStorage(TabEntries.third.rawValue) var thirdTab = Tab.explore @AppStorage(TabEntries.third.rawValue) var thirdTab = AppTab.explore
@AppStorage(TabEntries.fourth.rawValue) var fourthTab = Tab.links @AppStorage(TabEntries.fourth.rawValue) var fourthTab = AppTab.links
@AppStorage(TabEntries.fifth.rawValue) var fifthTab = Tab.profile @AppStorage(TabEntries.fifth.rawValue) var fifthTab = AppTab.profile
} }
private let storage = Storage() private let storage = Storage()
public static let shared = iOSTabs() public static let shared = iOSTabs()
var tabs: [Tab] { var tabs: [AppTab] {
[firstTab, secondTab, thirdTab, fourthTab, fifthTab] [firstTab, secondTab, thirdTab, fourthTab, fifthTab]
} }
var firstTab: Tab { var firstTab: AppTab {
didSet { didSet {
storage.firstTab = firstTab storage.firstTab = firstTab
} }
} }
var secondTab: Tab { var secondTab: AppTab {
didSet { didSet {
storage.secondTab = secondTab storage.secondTab = secondTab
} }
} }
var thirdTab: Tab { var thirdTab: AppTab {
didSet { didSet {
storage.thirdTab = thirdTab storage.thirdTab = thirdTab
} }
} }
var fourthTab: Tab { var fourthTab: AppTab {
didSet { didSet {
storage.fourthTab = fourthTab storage.fourthTab = fourthTab
} }
} }
var fifthTab: Tab { var fifthTab: AppTab {
didSet { didSet {
storage.fifthTab = fifthTab storage.fifthTab = fifthTab
} }

View file

@ -14,7 +14,6 @@ struct ExploreTab: View {
@Environment(Client.self) private var client @Environment(Client.self) private var client
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0 @State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
@ -28,15 +27,6 @@ struct ExploreTab: View {
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .explore {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -16,7 +16,6 @@ struct MessagesTab: View {
@Environment(AppAccountsManager.self) private var appAccount @Environment(AppAccountsManager.self) private var appAccount
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0 @State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
@ -29,15 +28,6 @@ struct MessagesTab: View {
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.id(client.id) .id(client.id)
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .messages {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -22,8 +22,7 @@ struct NotificationsTab: View {
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0 @State private var scrollToTopSignal: Int = 0
@Binding var selectedTab: Tab @Binding var selectedTab: AppTab
@Binding var popToRootTab: Tab
let lockedType: Models.Notification.NotificationType? let lockedType: Models.Notification.NotificationType?
@ -51,15 +50,6 @@ struct NotificationsTab: View {
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .notifications {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: selectedTab) { _, _ in .onChange(of: selectedTab) { _, _ in
clearNotifications() clearNotifications()
} }

View file

@ -15,7 +15,6 @@ struct ProfileTab: View {
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0 @State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
@ -31,15 +30,6 @@ struct ProfileTab: View {
.allowsHitTesting(false) .allowsHitTesting(false)
} }
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .profile {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -28,8 +28,6 @@ struct SettingsTabs: View {
@State private var cachedRemoved = false @State private var cachedRemoved = false
@State private var timelineCache = TimelineCache() @State private var timelineCache = TimelineCache()
@Binding var popToRootTab: Tab
let isModal: Bool let isModal: Bool
@State private var startingPoint: SettingsStartingPoint? = nil @State private var startingPoint: SettingsStartingPoint? = nil
@ -103,11 +101,6 @@ struct SettingsTabs: View {
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .notifications {
routerPath.path = []
}
}
} }
private var accountsSection: some View { private var accountsSection: some View {
@ -192,10 +185,6 @@ struct SettingsTabs: View {
NavigationLink(destination: TabbarEntriesSettingsView()) { NavigationLink(destination: TabbarEntriesSettingsView()) {
Label("settings.general.tabbarEntries", systemImage: "platter.filled.bottom.iphone") Label("settings.general.tabbarEntries", systemImage: "platter.filled.bottom.iphone")
} }
} else if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
NavigationLink(destination: SidebarEntriesSettingsView()) {
Label("settings.general.sidebarEntries", systemImage: "sidebar.squares.leading")
}
} }
NavigationLink(destination: TranslationSettingsView()) { NavigationLink(destination: TranslationSettingsView()) {
Label("settings.general.translate", systemImage: "captions.bubble") Label("settings.general.translate", systemImage: "captions.bubble")

View file

@ -1,40 +0,0 @@
import DesignSystem
import Env
import SwiftUI
@MainActor
struct SidebarEntriesSettingsView: View {
@Environment(Theme.self) private var theme
@Environment(UserPreferences.self) private var userPreferences
@State private var sidebarTabs = SidebarTabs.shared
var body: some View {
@Bindable var userPreferences = userPreferences
Form {
Section {
ForEach($sidebarTabs.tabs, id: \.tab) { $tab in
if tab.tab != .profile && tab.tab != .settings {
Toggle(isOn: $tab.enabled) {
tab.tab.label
}
}
}
.onMove(perform: move)
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
.environment(\.editMode, .constant(.active))
.navigationTitle("settings.general.sidebarEntries")
#if !os(visionOS)
.scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor)
#endif
}
func move(from source: IndexSet, to destination: Int) {
sidebarTabs.tabs.move(fromOffsets: source, toOffset: destination)
}
}

View file

@ -14,27 +14,27 @@ struct TabbarEntriesSettingsView: View {
Form { Form {
Section { Section {
Picker("settings.tabs.first-tab", selection: $tabs.firstTab) { Picker("settings.tabs.first-tab", selection: $tabs.firstTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) tab.label.tag(tab)
} }
} }
Picker("settings.tabs.second-tab", selection: $tabs.secondTab) { Picker("settings.tabs.second-tab", selection: $tabs.secondTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) tab.label.tag(tab)
} }
} }
Picker("settings.tabs.third-tab", selection: $tabs.thirdTab) { Picker("settings.tabs.third-tab", selection: $tabs.thirdTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) tab.label.tag(tab)
} }
} }
Picker("settings.tabs.fourth-tab", selection: $tabs.fourthTab) { Picker("settings.tabs.fourth-tab", selection: $tabs.fourthTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) tab.label.tag(tab)
} }
} }
Picker("settings.tabs.fifth-tab", selection: $tabs.fifthTab) { Picker("settings.tabs.fifth-tab", selection: $tabs.fifthTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) tab.label.tag(tab)
} }
} }

View file

@ -18,7 +18,6 @@ struct TimelineTab: View {
@Environment(UserPreferences.self) private var preferences @Environment(UserPreferences.self) private var preferences
@Environment(Client.self) private var client @Environment(Client.self) private var client
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
@State private var didAppear: Bool = false @State private var didAppear: Bool = false
@State private var timeline: TimelineFilter = .home @State private var timeline: TimelineFilter = .home
@ -33,9 +32,8 @@ struct TimelineTab: View {
private let canFilterTimeline: Bool private let canFilterTimeline: Bool
init(popToRootTab: Binding<Tab>, timeline: TimelineFilter? = nil) { init(timeline: TimelineFilter? = nil) {
canFilterTimeline = timeline == nil canFilterTimeline = timeline == nil
_popToRootTab = popToRootTab
_timeline = .init(initialValue: timeline ?? .home) _timeline = .init(initialValue: timeline ?? .home)
} }
@ -77,15 +75,6 @@ struct TimelineTab: View {
.onChange(of: currentAccount.account?.id) { .onChange(of: currentAccount.account?.id) {
resetTimelineFilter() resetTimelineFilter()
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .timeline {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -15,29 +15,10 @@ struct ToolbarTab: ToolbarContent {
var body: some ToolbarContent { var body: some ToolbarContent {
if !isSecondaryColumn { if !isSecondaryColumn {
ToolbarItem(placement: .topBarLeading) {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
Button {
withAnimation {
userPreferences.isSidebarExpanded.toggle()
}
} label: {
if userPreferences.isSidebarExpanded {
Image(systemName: "sidebar.squares.left")
} else {
Image(systemName: "sidebar.left")
}
}
}
}
statusEditorToolbarItem(routerPath: routerPath, statusEditorToolbarItem(routerPath: routerPath,
visibility: userPreferences.postVisibility) visibility: userPreferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad || ToolbarItem(placement: .navigationBarLeading) {
(UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact) AppAccountsSelectorView(routerPath: routerPath, avatarConfig: theme.avatarShape == .circle ? .badge : .badgeRounded)
{
ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath, avatarConfig: theme.avatarShape == .circle ? .badge : .badgeRounded)
}
} }
} }
if UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .regular { if UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .regular {

View file

@ -77330,6 +77330,7 @@
} }
}, },
"tab.profile-account-%@" : { "tab.profile-account-%@" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"be" : { "be" : {
"stringUnit" : { "stringUnit" : {

View file

@ -35,7 +35,7 @@ enum TabEnum: String, AppEnum, Sendable {
.post: .init(title: "New post")] .post: .init(title: "New post")]
} }
var toAppTab: Tab { var toAppTab: AppTab {
switch self { switch self {
case .timeline: case .timeline:
.timeline .timeline

View file

@ -23,8 +23,11 @@ struct AccountWidgetProvider: AppIntentTimelineProvider {
} }
private func fetchAccount(configuration: AccountWidgetConfiguration) async -> Account { private func fetchAccount(configuration: AccountWidgetConfiguration) async -> Account {
let client = Client(server: configuration.account.account.server, guard let account = configuration.account else {
oauthToken: configuration.account.account.oauthToken) return .placeholder()
}
let client = Client(server: account.account.server,
oauthToken: account.account.oauthToken)
do { do {
let account: Account = try await client.get(endpoint: Accounts.verifyCredentials) let account: Account = try await client.get(endpoint: Accounts.verifyCredentials)
return account return account

View file

@ -6,7 +6,7 @@ struct AccountWidgetConfiguration: WidgetConfigurationIntent {
static let description = IntentDescription("Choose the account for this widget") static let description = IntentDescription("Choose the account for this widget")
@Parameter(title: "Account") @Parameter(title: "Account")
var account: AppAccountEntity var account: AppAccountEntity?
} }
extension AccountWidgetConfiguration { extension AccountWidgetConfiguration {

View file

@ -29,9 +29,16 @@ struct HashtagPostsWidgetProvider: AppIntentTimelineProvider {
private func timeline(for configuration: HashtagPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> { private func timeline(for configuration: HashtagPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
do { do {
let timeline: TimelineFilter = .hashtag(tag: configuration.hashgtag, accountId: nil) guard let account = configuration.account, let hashgtag = configuration.hashgtag else {
return Timeline(entries: [.init(date: Date(),
title: "#Mastodon",
statuses: [],
images: [:])],
policy: .atEnd)
}
let timeline: TimelineFilter = .hashtag(tag: hashgtag, accountId: nil)
let statuses = await loadStatuses(for: timeline, let statuses = await loadStatuses(for: timeline,
account: configuration.account, account: account,
widgetFamily: context.family) widgetFamily: context.family)
let images = try await loadImages(urls: statuses.map { $0.account.avatar }) let images = try await loadImages(urls: statuses.map { $0.account.avatar })
return Timeline(entries: [.init(date: Date(), return Timeline(entries: [.init(date: Date(),

View file

@ -6,10 +6,10 @@ struct HashtagPostsWidgetConfiguration: WidgetConfigurationIntent {
static let description = IntentDescription("Choose the account and hashtag for this widget") static let description = IntentDescription("Choose the account and hashtag for this widget")
@Parameter(title: "Account") @Parameter(title: "Account")
var account: AppAccountEntity var account: AppAccountEntity?
@Parameter(title: "Hashtag") @Parameter(title: "Hashtag")
var hashgtag: String var hashgtag: String?
} }
extension HashtagPostsWidgetConfiguration { extension HashtagPostsWidgetConfiguration {

View file

@ -18,7 +18,7 @@ struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
return entry return entry
} }
return .init(date: Date(), return .init(date: Date(),
title: configuration.timeline.timeline.title, title: configuration.timeline?.timeline.title ?? "",
statuses: [], statuses: [],
images: [:]) images: [:])
} }
@ -29,17 +29,24 @@ struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
private func timeline(for configuration: LatestPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> { private func timeline(for configuration: LatestPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
do { do {
let statuses = await loadStatuses(for: configuration.timeline.timeline, guard let timeline = configuration.timeline, let account = configuration.account else {
account: configuration.account, return Timeline(entries: [.init(date: Date(),
title: "",
statuses: [],
images: [:])],
policy: .atEnd)
}
let statuses = await loadStatuses(for: timeline.timeline,
account: account,
widgetFamily: context.family) widgetFamily: context.family)
let images = try await loadImages(urls: statuses.map { $0.account.avatar }) let images = try await loadImages(urls: statuses.map { $0.account.avatar })
return Timeline(entries: [.init(date: Date(), return Timeline(entries: [.init(date: Date(),
title: configuration.timeline.timeline.title, title: timeline.timeline.title,
statuses: statuses, statuses: statuses,
images: images)], policy: .atEnd) images: images)], policy: .atEnd)
} catch { } catch {
return Timeline(entries: [.init(date: Date(), return Timeline(entries: [.init(date: Date(),
title: configuration.timeline.timeline.title, title: configuration.timeline?.timeline.title ?? "",
statuses: [], statuses: [],
images: [:])], images: [:])],
policy: .atEnd) policy: .atEnd)

View file

@ -6,10 +6,10 @@ struct LatestPostsWidgetConfiguration: WidgetConfigurationIntent {
static let description = IntentDescription("Choose the account and timeline for this widget") static let description = IntentDescription("Choose the account and timeline for this widget")
@Parameter(title: "Account") @Parameter(title: "Account")
var account: AppAccountEntity var account: AppAccountEntity?
@Parameter(title: "Timeline") @Parameter(title: "Timeline")
var timeline: TimelineFilterEntity var timeline: TimelineFilterEntity?
} }
extension LatestPostsWidgetConfiguration { extension LatestPostsWidgetConfiguration {

View file

@ -29,13 +29,20 @@ struct ListsWidgetProvider: AppIntentTimelineProvider {
private func timeline(for configuration: ListsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> { private func timeline(for configuration: ListsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
do { do {
let timeline: TimelineFilter = .list(list: configuration.timeline.list) guard let account = configuration.account, let timeline = configuration.timeline else {
let statuses = await loadStatuses(for: timeline, return Timeline(entries: [.init(date: Date(),
account: configuration.account, title: "List name",
statuses: [],
images: [:])],
policy: .atEnd)
}
let filter: TimelineFilter = .list(list: timeline.list)
let statuses = await loadStatuses(for: filter,
account: account,
widgetFamily: context.family) widgetFamily: context.family)
let images = try await loadImages(urls: statuses.map { $0.account.avatar }) let images = try await loadImages(urls: statuses.map { $0.account.avatar })
return Timeline(entries: [.init(date: Date(), return Timeline(entries: [.init(date: Date(),
title: timeline.title, title: filter.title,
statuses: statuses, statuses: statuses,
images: images)], policy: .atEnd) images: images)], policy: .atEnd)
} catch { } catch {

View file

@ -6,10 +6,10 @@ struct ListsWidgetConfiguration: WidgetConfigurationIntent {
static let description = IntentDescription("Choose the account and list for this widget") static let description = IntentDescription("Choose the account and list for this widget")
@Parameter(title: "Account") @Parameter(title: "Account")
var account: AppAccountEntity var account: AppAccountEntity?
@Parameter(title: "List") @Parameter(title: "List")
var timeline: ListEntity var timeline: ListEntity?
} }
extension ListsWidgetConfiguration { extension ListsWidgetConfiguration {

View file

@ -29,8 +29,15 @@ struct MentionsWidgetProvider: AppIntentTimelineProvider {
private func timeline(for configuration: MentionsWidgetConfiguration, context _: Context) async -> Timeline<PostsWidgetEntry> { private func timeline(for configuration: MentionsWidgetConfiguration, context _: Context) async -> Timeline<PostsWidgetEntry> {
do { do {
let client = Client(server: configuration.account.account.server, guard let account = configuration.account else {
oauthToken: configuration.account.account.oauthToken) return Timeline(entries: [.init(date: Date(),
title: "Mentions",
statuses: [],
images: [:])],
policy: .atEnd)
}
let client = Client(server: account.account.server,
oauthToken: account.account.oauthToken)
var excludedTypes = Models.Notification.NotificationType.allCases var excludedTypes = Models.Notification.NotificationType.allCases
excludedTypes.removeAll(where: { $0 == .mention }) excludedTypes.removeAll(where: { $0 == .mention })
let notifications: [Models.Notification] = let notifications: [Models.Notification] =

View file

@ -6,7 +6,7 @@ struct MentionsWidgetConfiguration: WidgetConfigurationIntent {
static let description = IntentDescription("Choose the account for this widget") static let description = IntentDescription("Choose the account for this widget")
@Parameter(title: "Account") @Parameter(title: "Account")
var account: AppAccountEntity var account: AppAccountEntity?
} }
extension MentionsWidgetConfiguration { extension MentionsWidgetConfiguration {

View file

@ -49,12 +49,21 @@ public struct AppAccountsSelectorView: View {
.contentShape(Rectangle()) .contentShape(Rectangle())
} }
.sheet(isPresented: $isPresented, content: { .sheet(isPresented: $isPresented, content: {
accountsView.presentationDetents([.height(preferredHeight), .large]) if UIDevice.current.userInterfaceIdiom == .mac || UIDevice.current.userInterfaceIdiom == .pad {
.presentationBackground(.ultraThinMaterial) accountsView
.presentationCornerRadius(16) .presentationBackground(.ultraThinMaterial)
.onAppear { .onAppear {
refreshAccounts() refreshAccounts()
} }
} else {
accountsView
.presentationDetents([.height(preferredHeight), .large])
.presentationBackground(.ultraThinMaterial)
.presentationCornerRadius(16)
.onAppear {
refreshAccounts()
}
}
}) })
.onChange(of: currentAccount.account?.id) { .onChange(of: currentAccount.account?.id) {
refreshAccounts() refreshAccounts()