Switch to NavigationStack
Changelog-Changed: Drop iOS15 support Changelog-Fixed: Fixed navigation popping issues
This commit is contained in:
@@ -304,6 +304,7 @@
|
|||||||
9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */; };
|
9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */; };
|
||||||
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
||||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
|
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
|
||||||
|
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; };
|
||||||
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; };
|
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; };
|
||||||
E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */; };
|
E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */; };
|
||||||
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; };
|
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; };
|
||||||
@@ -753,6 +754,7 @@
|
|||||||
9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachMediaUtility.swift; sourceTree = "<group>"; };
|
9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachMediaUtility.swift; sourceTree = "<group>"; };
|
||||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
|
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
|
||||||
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
|
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
|
||||||
|
D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
|
||||||
DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; };
|
DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; };
|
||||||
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = "<group>"; };
|
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = "<group>"; };
|
||||||
E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; };
|
E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; };
|
||||||
@@ -1155,6 +1157,7 @@
|
|||||||
50B5685229F97CB400A23243 /* CredentialHandler.swift */,
|
50B5685229F97CB400A23243 /* CredentialHandler.swift */,
|
||||||
4C7D09582A05BEAD00943473 /* KeyboardVisible.swift */,
|
4C7D09582A05BEAD00943473 /* KeyboardVisible.swift */,
|
||||||
3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */,
|
3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */,
|
||||||
|
D2277EE92A089BD5006C3807 /* Router.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1307,7 +1310,9 @@
|
|||||||
4CE6DEE427F7A08100C66700 /* Products */,
|
4CE6DEE427F7A08100C66700 /* Products */,
|
||||||
4CEE2AE62804F57B00AB5EEF /* Frameworks */,
|
4CEE2AE62804F57B00AB5EEF /* Frameworks */,
|
||||||
);
|
);
|
||||||
|
indentWidth = 4;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
tabWidth = 4;
|
||||||
};
|
};
|
||||||
4CE6DEE427F7A08100C66700 /* Products */ = {
|
4CE6DEE427F7A08100C66700 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
@@ -1861,6 +1866,7 @@
|
|||||||
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */,
|
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */,
|
||||||
4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */,
|
4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */,
|
||||||
3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */,
|
3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */,
|
||||||
|
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */,
|
||||||
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
||||||
4CE1399429F0669900AC6A0B /* BigButton.swift in Sources */,
|
4CE1399429F0669900AC6A0B /* BigButton.swift in Sources */,
|
||||||
7C60CAEF298471A1009C80D6 /* CoreSVG.swift in Sources */,
|
7C60CAEF298471A1009C80D6 /* CoreSVG.swift in Sources */,
|
||||||
@@ -2254,6 +2260,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard;
|
INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -2302,6 +2309,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard;
|
INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|||||||
@@ -11,21 +11,10 @@ struct UserViewRow: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let pubkey: String
|
let pubkey: String
|
||||||
|
|
||||||
@State var navigating: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let dest = ProfileView(damus_state: damus_state, pubkey: pubkey)
|
|
||||||
|
|
||||||
UserView(damus_state: damus_state, pubkey: pubkey)
|
UserView(damus_state: damus_state, pubkey: pubkey)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.background(
|
.background(.clear)
|
||||||
NavigationLink(destination: dest, isActive: $navigating) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
navigating = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-62
@@ -82,14 +82,6 @@ struct ContentView: View {
|
|||||||
@State var damus_state: DamusState? = nil
|
@State var damus_state: DamusState? = nil
|
||||||
@SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home
|
@SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home
|
||||||
@State var is_deleted_account: Bool = false
|
@State var is_deleted_account: Bool = false
|
||||||
@State var active_profile: String? = nil
|
|
||||||
@State var active_search: NostrFilter? = nil
|
|
||||||
@State var active_event: NostrEvent? = nil
|
|
||||||
@State var profile_open: Bool = false
|
|
||||||
@State var thread_open: Bool = false
|
|
||||||
@State var search_open: Bool = false
|
|
||||||
@State var wallet_open: Bool = false
|
|
||||||
@State var active_nwc: WalletConnectURL? = nil
|
|
||||||
@State var muting: String? = nil
|
@State var muting: String? = nil
|
||||||
@State var confirm_mute: Bool = false
|
@State var confirm_mute: Bool = false
|
||||||
@State var user_muted_confirm: Bool = false
|
@State var user_muted_confirm: Bool = false
|
||||||
@@ -97,6 +89,7 @@ struct ContentView: View {
|
|||||||
@SceneStorage("ContentView.filter_state") var filter_state : FilterState = .posts_and_replies
|
@SceneStorage("ContentView.filter_state") var filter_state : FilterState = .posts_and_replies
|
||||||
@State private var isSideBarOpened = false
|
@State private var isSideBarOpened = false
|
||||||
var home: HomeModel = HomeModel()
|
var home: HomeModel = HomeModel()
|
||||||
|
@StateObject var navigationCoordinator: NavigationCoordinator = NavigationCoordinator()
|
||||||
|
|
||||||
let sub_id = UUID().description
|
let sub_id = UUID().description
|
||||||
|
|
||||||
@@ -150,15 +143,13 @@ struct ContentView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
if let damus = self.damus_state {
|
if let damus = self.damus_state {
|
||||||
TimelineView(events: home.events, loading: .constant(false), damus: damus, show_friend_icon: false, filter: filter)
|
TimelineView(events: home.events, loading: .constant(false), damus: damus, show_friend_icon: false, filter: filter)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func popToRoot() {
|
func popToRoot() {
|
||||||
profile_open = false
|
navigationCoordinator.popToRoot()
|
||||||
thread_open = false
|
|
||||||
search_open = false
|
|
||||||
wallet_open = false
|
|
||||||
isSideBarOpened = false
|
isSideBarOpened = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,29 +160,16 @@ struct ContentView: View {
|
|||||||
|
|
||||||
func MainContent(damus: DamusState) -> some View {
|
func MainContent(damus: DamusState) -> some View {
|
||||||
VStack {
|
VStack {
|
||||||
NavigationLink(destination: WalletView(damus_state: damus, model: damus_state!.wallet), isActive: $wallet_open) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
NavigationLink(destination: MaybeProfileView, isActive: $profile_open) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
if let active_event {
|
|
||||||
let thread = ThreadModel(event: active_event, damus_state: damus_state!)
|
|
||||||
NavigationLink(destination: ThreadView(state: damus_state!, thread: thread), isActive: $thread_open) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NavigationLink(destination: MaybeSearchView, isActive: $search_open) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
switch selected_timeline {
|
switch selected_timeline {
|
||||||
case .search:
|
case .search:
|
||||||
if #available(iOS 16.0, *) {
|
if #available(iOS 16.0, *) {
|
||||||
SearchHomeView(damus_state: damus_state!, model: SearchHomeModel(damus_state: damus_state!))
|
SearchHomeView(damus_state: damus_state!, model: SearchHomeModel(damus_state: damus_state!))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.scrollDismissesKeyboard(.immediately)
|
.scrollDismissesKeyboard(.immediately)
|
||||||
} else {
|
} else {
|
||||||
// Fallback on earlier versions
|
// Fallback on earlier versions
|
||||||
SearchHomeView(damus_state: damus_state!, model: SearchHomeModel(damus_state: damus_state!))
|
SearchHomeView(damus_state: damus_state!, model: SearchHomeModel(damus_state: damus_state!))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .home:
|
case .home:
|
||||||
@@ -199,9 +177,11 @@ struct ContentView: View {
|
|||||||
|
|
||||||
case .notifications:
|
case .notifications:
|
||||||
NotificationsView(state: damus, notifications: home.notifications)
|
NotificationsView(state: damus, notifications: home.notifications)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .dms:
|
case .dms:
|
||||||
DirectMessagesView(damus_state: damus_state!, model: damus_state!.dms, settings: damus_state!.settings)
|
DirectMessagesView(damus_state: damus_state!, model: damus_state!.dms, settings: damus_state!.settings)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitle(timeline_name(selected_timeline), displayMode: .inline)
|
.navigationBarTitle(timeline_name(selected_timeline), displayMode: .inline)
|
||||||
@@ -225,28 +205,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var MaybeSearchView: some View {
|
|
||||||
Group {
|
|
||||||
if let search = self.active_search {
|
|
||||||
SearchView(appstate: damus_state!, search: SearchModel(state: damus_state!, search: search))
|
|
||||||
} else {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var MaybeProfileView: some View {
|
|
||||||
Group {
|
|
||||||
if let pk = self.active_profile {
|
|
||||||
let profile_model = ProfileModel(pubkey: pk, damus: damus_state!)
|
|
||||||
let followers = FollowersModel(damus_state: damus_state!, target: pk)
|
|
||||||
ProfileView(damus_state: damus_state!, profile: profile_model, followers: followers)
|
|
||||||
} else {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MaybeReportView(target: ReportTarget) -> some View {
|
func MaybeReportView(target: ReportTarget) -> some View {
|
||||||
Group {
|
Group {
|
||||||
if let damus_state {
|
if let damus_state {
|
||||||
@@ -262,32 +220,30 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func open_event(ev: NostrEvent) {
|
func open_event(ev: NostrEvent) {
|
||||||
popToRoot()
|
let thread = ThreadModel(event: ev, damus_state: damus_state!)
|
||||||
self.active_event = ev
|
navigationCoordinator.push(route: Route.Thread(thread: thread))
|
||||||
self.thread_open = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func open_wallet(nwc: WalletConnectURL) {
|
func open_wallet(nwc: WalletConnectURL) {
|
||||||
self.damus_state!.wallet.new(nwc)
|
self.damus_state!.wallet.new(nwc)
|
||||||
self.wallet_open = true
|
navigationCoordinator.push(route: Route.Wallet(wallet: damus_state!.wallet))
|
||||||
}
|
}
|
||||||
|
|
||||||
func open_profile(id: String) {
|
func open_profile(id: String) {
|
||||||
popToRoot()
|
let profile_model = ProfileModel(pubkey: id, damus: damus_state!)
|
||||||
self.active_profile = id
|
let followers = FollowersModel(damus_state: damus_state!, target: id)
|
||||||
self.profile_open = true
|
navigationCoordinator.push(route: Route.Profile(profile: profile_model, followers: followers))
|
||||||
}
|
}
|
||||||
|
|
||||||
func open_search(filt: NostrFilter) {
|
func open_search(filt: NostrFilter) {
|
||||||
popToRoot()
|
let search = SearchModel(state: damus_state!, search: filt)
|
||||||
self.active_search = filt
|
navigationCoordinator.push(route: Route.Search(search: search))
|
||||||
self.search_open = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
if let damus = self.damus_state {
|
if let damus = self.damus_state {
|
||||||
NavigationView {
|
NavigationStack(path: $navigationCoordinator.path) {
|
||||||
TabView { // Prevents navbar appearance change on scroll
|
TabView { // Prevents navbar appearance change on scroll
|
||||||
MainContent(damus: damus)
|
MainContent(damus: damus)
|
||||||
.toolbar() {
|
.toolbar() {
|
||||||
@@ -326,7 +282,14 @@ struct ContentView: View {
|
|||||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||||
.overlay(
|
.overlay(
|
||||||
SideMenuView(damus_state: damus, isSidebarVisible: $isSideBarOpened.animation())
|
SideMenuView(damus_state: damus, isSidebarVisible: $isSideBarOpened.animation())
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
)
|
)
|
||||||
|
.navigationDestination(for: Route.self) { route in
|
||||||
|
route.view(navigationCordinator: navigationCoordinator, damusState: damus_state!)
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||||
|
navigationCoordinator.popToRoot()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationViewStyle(.stack)
|
.navigationViewStyle(.stack)
|
||||||
|
|
||||||
@@ -520,8 +483,8 @@ struct ContentView: View {
|
|||||||
switch local.type {
|
switch local.type {
|
||||||
case .dm:
|
case .dm:
|
||||||
selected_timeline = .dms
|
selected_timeline = .dms
|
||||||
damus_state.dms.open_dm_by_pk(target.pubkey)
|
damus_state.dms.set_active_dm(target.pubkey)
|
||||||
|
navigationCoordinator.push(route: Route.DMChat(dms: damus_state.dms.active_model))
|
||||||
case .like: fallthrough
|
case .like: fallthrough
|
||||||
case .zap: fallthrough
|
case .zap: fallthrough
|
||||||
case .mention: fallthrough
|
case .mention: fallthrough
|
||||||
|
|||||||
@@ -30,16 +30,6 @@ class DirectMessagesModel: ObservableObject {
|
|||||||
self.active_model = model
|
self.active_model = model
|
||||||
}
|
}
|
||||||
|
|
||||||
func open_dm_by_pk(_ pubkey: String) {
|
|
||||||
self.set_active_dm(pubkey)
|
|
||||||
self.open_dm = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func open_dm_by_model(_ model: DirectMessageModel) {
|
|
||||||
self.set_active_dm_model(model)
|
|
||||||
self.open_dm = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func set_active_dm(_ pubkey: String) {
|
func set_active_dm(_ pubkey: String) {
|
||||||
for model in self.dms where model.pubkey == pubkey {
|
for model in self.dms where model.pubkey == pubkey {
|
||||||
self.set_active_dm_model(model)
|
self.set_active_dm_model(model)
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
//
|
||||||
|
// Router.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Scott Penrose on 5/7/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
enum Route: Hashable {
|
||||||
|
case ProfileByKey(pubkey: String)
|
||||||
|
case Profile(profile: ProfileModel, followers: FollowersModel)
|
||||||
|
case Followers(environmentObject: FollowersModel)
|
||||||
|
case Relay(relay: String, showActionButtons: Binding<Bool>)
|
||||||
|
case RelayDetail(relay: String, metadata: RelayMetadata)
|
||||||
|
case Following(following: FollowingModel)
|
||||||
|
case MuteList(users: [String])
|
||||||
|
case RelayConfig
|
||||||
|
case Bookmarks
|
||||||
|
case Config
|
||||||
|
case EditMetadata
|
||||||
|
case DMChat(dms: DirectMessageModel)
|
||||||
|
case UserRelays(relays: [String])
|
||||||
|
case KeySettings(keypair: Keypair)
|
||||||
|
case AppearanceSettings(settings: UserSettingsStore)
|
||||||
|
case NotificationSettings(settings: UserSettingsStore)
|
||||||
|
case ZapSettings(settings: UserSettingsStore)
|
||||||
|
case TranslationSettings(settings: UserSettingsStore)
|
||||||
|
case SearchSettings(settings: UserSettingsStore)
|
||||||
|
case Thread(thread: ThreadModel)
|
||||||
|
case Reposts(reposts: RepostsModel)
|
||||||
|
case Reactions(reactions: ReactionsModel)
|
||||||
|
case Zaps(target: ZapTarget)
|
||||||
|
case Search(search: SearchModel)
|
||||||
|
case EULA
|
||||||
|
case Login
|
||||||
|
case CreateAccount
|
||||||
|
case SaveKeys(account: CreateAccountModel)
|
||||||
|
case Wallet(wallet: WalletModel)
|
||||||
|
case WalletScanner(result: Binding<WalletScanResult>)
|
||||||
|
case FollowersYouKnow(friendedFollowers: [String])
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func view(navigationCordinator: NavigationCoordinator, damusState: DamusState) -> some View {
|
||||||
|
switch self {
|
||||||
|
case .ProfileByKey(let pubkey):
|
||||||
|
ProfileView(damus_state: damusState, pubkey: pubkey)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Profile(let profile, let followers):
|
||||||
|
ProfileView(damus_state: damusState, profile: profile, followers: followers)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Followers(let environmentObject):
|
||||||
|
FollowersView(damus_state: damusState)
|
||||||
|
.environmentObject(environmentObject)
|
||||||
|
case .Relay(let relay, let showActionButtons):
|
||||||
|
RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons)
|
||||||
|
case .RelayDetail(let relay, let metadata):
|
||||||
|
RelayDetailView(state: damusState, relay: relay, nip11: metadata)
|
||||||
|
case .Following(let following):
|
||||||
|
FollowingView(damus_state: damusState, following: following)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .MuteList(let users):
|
||||||
|
MutelistView(damus_state: damusState, users: users)
|
||||||
|
case .RelayConfig:
|
||||||
|
RelayConfigView(state: damusState)
|
||||||
|
case .Bookmarks:
|
||||||
|
BookmarksView(state: damusState)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Config:
|
||||||
|
ConfigView(state: damusState)
|
||||||
|
case .EditMetadata:
|
||||||
|
EditMetadataView(damus_state: damusState)
|
||||||
|
case .DMChat(let dms):
|
||||||
|
DMChatView(damus_state: damusState, dms: dms)
|
||||||
|
case .UserRelays(let relays):
|
||||||
|
UserRelaysView(state: damusState, relays: relays)
|
||||||
|
case .KeySettings(let keypair):
|
||||||
|
KeySettingsView(keypair: keypair)
|
||||||
|
case .AppearanceSettings(let settings):
|
||||||
|
AppearanceSettingsView(settings: settings)
|
||||||
|
case .NotificationSettings(let settings):
|
||||||
|
NotificationSettingsView(settings: settings)
|
||||||
|
case .ZapSettings(let settings):
|
||||||
|
ZapSettingsView(settings: settings)
|
||||||
|
case .TranslationSettings(let settings):
|
||||||
|
NotificationSettingsView(settings: settings)
|
||||||
|
case .SearchSettings(let settings):
|
||||||
|
SearchSettingsView(settings: settings)
|
||||||
|
case .Thread(let thread):
|
||||||
|
ThreadView(state: damusState, thread: thread)
|
||||||
|
case .Reposts(let reposts):
|
||||||
|
RepostsView(damus_state: damusState, model: reposts)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Reactions(let reactions):
|
||||||
|
ReactionsView(damus_state: damusState, model: reactions)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Zaps(let target):
|
||||||
|
ZapsView(state: damusState, target: target)
|
||||||
|
case .Search(let search):
|
||||||
|
SearchView(appstate: damusState, search: search)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .EULA:
|
||||||
|
EULAView()
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Login:
|
||||||
|
LoginView()
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .CreateAccount:
|
||||||
|
CreateAccountView()
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .SaveKeys(let account):
|
||||||
|
SaveKeysView(account: account)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .Wallet(let walletModel):
|
||||||
|
WalletView(damus_state: damusState, model: walletModel)
|
||||||
|
.environmentObject(navigationCordinator)
|
||||||
|
case .WalletScanner(let walletScanResult):
|
||||||
|
WalletScannerView(result: walletScanResult)
|
||||||
|
case .FollowersYouKnow(let friendedFollowers):
|
||||||
|
FollowersYouKnowView(damus_state: damusState, friended_followers: friendedFollowers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func == (lhs: Route, rhs: Route) -> Bool {
|
||||||
|
switch (lhs, rhs) {
|
||||||
|
case (.ProfileByKey (let lhs_pubkey), .ProfileByKey(let rhs_pubkey)):
|
||||||
|
return lhs_pubkey == rhs_pubkey
|
||||||
|
case (.Profile (let lhs_profile, _), .Profile(let rhs_profile, _)):
|
||||||
|
return lhs_profile == rhs_profile
|
||||||
|
case (.Followers (_), .Followers (_)):
|
||||||
|
return true
|
||||||
|
case (.Relay (let lhs_relay, _), .Relay (let rhs_relay, _)):
|
||||||
|
return lhs_relay == rhs_relay
|
||||||
|
case (.RelayDetail(let lhs_relay, _), .RelayDetail(let rhs_relay, _)):
|
||||||
|
return lhs_relay == rhs_relay
|
||||||
|
case (.Following(_), .Following(_)):
|
||||||
|
return true
|
||||||
|
case (.MuteList(let lhs_users), .MuteList(let rhs_users)):
|
||||||
|
return lhs_users == rhs_users
|
||||||
|
case (.RelayConfig, .RelayConfig):
|
||||||
|
return true
|
||||||
|
case (.Bookmarks, .Bookmarks):
|
||||||
|
return true
|
||||||
|
case (.Config, .Config):
|
||||||
|
return true
|
||||||
|
case (.EditMetadata, .EditMetadata):
|
||||||
|
return true
|
||||||
|
case (.DMChat(let lhs_dms), .DMChat(let rhs_dms)):
|
||||||
|
return lhs_dms.our_pubkey == rhs_dms.our_pubkey
|
||||||
|
case (.UserRelays(let lhs_relays), .UserRelays(let rhs_relays)):
|
||||||
|
return lhs_relays == rhs_relays
|
||||||
|
case (.KeySettings(let lhs_keypair), .KeySettings(let rhs_keypair)):
|
||||||
|
return lhs_keypair.pubkey == rhs_keypair.pubkey
|
||||||
|
case (.AppearanceSettings(_), .AppearanceSettings(_)):
|
||||||
|
return true
|
||||||
|
case (.NotificationSettings(_), .NotificationSettings(_)):
|
||||||
|
return true
|
||||||
|
case (.ZapSettings(_), .ZapSettings(_)):
|
||||||
|
return true
|
||||||
|
case (.TranslationSettings(_), .TranslationSettings(_)):
|
||||||
|
return true
|
||||||
|
case (.SearchSettings(_), .SearchSettings(_)):
|
||||||
|
return true
|
||||||
|
case (.Thread(let lhs_threadModel), .Thread(thread: let rhs_threadModel)):
|
||||||
|
return lhs_threadModel.event.id == rhs_threadModel.event.id
|
||||||
|
case (.Reposts(let lhs_reposts), .Reposts(let rhs_reposts)):
|
||||||
|
return lhs_reposts.target == rhs_reposts.target
|
||||||
|
case (.Reactions(let lhs_reactions), .Reactions(let rhs_reactions)):
|
||||||
|
return lhs_reactions.target == rhs_reactions.target
|
||||||
|
case (.Zaps(let lhs_target), .Zaps(let rhs_target)):
|
||||||
|
return lhs_target == rhs_target
|
||||||
|
case (.Search(let lhs_search), .Search(let rhs_search)):
|
||||||
|
return lhs_search.sub_id == rhs_search.sub_id && lhs_search.profiles_subid == rhs_search.profiles_subid
|
||||||
|
case (.EULA, .EULA):
|
||||||
|
return true
|
||||||
|
case (.Login, .Login):
|
||||||
|
return true
|
||||||
|
case (.CreateAccount, .CreateAccount):
|
||||||
|
return true
|
||||||
|
case (.SaveKeys(let lhs_account), .SaveKeys(let rhs_account)):
|
||||||
|
return lhs_account.pubkey == rhs_account.pubkey
|
||||||
|
case (.Wallet(_), .Wallet(_)):
|
||||||
|
return true
|
||||||
|
case (.WalletScanner(_), .WalletScanner(_)):
|
||||||
|
return true
|
||||||
|
case (.FollowersYouKnow(let lhs_friendedFollowers), .FollowersYouKnow(let rhs_friendedFollowers)):
|
||||||
|
return lhs_friendedFollowers == rhs_friendedFollowers
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hash(into hasher: inout Hasher) {
|
||||||
|
switch self {
|
||||||
|
case .ProfileByKey(let pubkey):
|
||||||
|
hasher.combine("profilebykey")
|
||||||
|
hasher.combine(pubkey)
|
||||||
|
case .Profile(let profile, _):
|
||||||
|
hasher.combine("profile")
|
||||||
|
hasher.combine(profile.pubkey)
|
||||||
|
case .Followers(_):
|
||||||
|
hasher.combine("followers")
|
||||||
|
case .Relay(let relay, _):
|
||||||
|
hasher.combine("relay")
|
||||||
|
hasher.combine(relay)
|
||||||
|
case .RelayDetail(let relay, _):
|
||||||
|
hasher.combine("relayDetail")
|
||||||
|
hasher.combine(relay)
|
||||||
|
case .Following(_):
|
||||||
|
hasher.combine("following")
|
||||||
|
case .MuteList(let users):
|
||||||
|
hasher.combine("muteList")
|
||||||
|
hasher.combine(users)
|
||||||
|
case .RelayConfig:
|
||||||
|
hasher.combine("relayConfig")
|
||||||
|
case .Bookmarks:
|
||||||
|
hasher.combine("bookmarks")
|
||||||
|
case .Config:
|
||||||
|
hasher.combine("config")
|
||||||
|
case .EditMetadata:
|
||||||
|
hasher.combine("editMetadata")
|
||||||
|
case .DMChat(let dms):
|
||||||
|
hasher.combine("dms")
|
||||||
|
hasher.combine(dms.our_pubkey)
|
||||||
|
case .UserRelays(let relays):
|
||||||
|
hasher.combine("userRelays")
|
||||||
|
hasher.combine(relays)
|
||||||
|
case .KeySettings(let keypair):
|
||||||
|
hasher.combine("keySettings")
|
||||||
|
hasher.combine(keypair.pubkey)
|
||||||
|
case .AppearanceSettings(_):
|
||||||
|
hasher.combine("appearanceSettings")
|
||||||
|
case .NotificationSettings(_):
|
||||||
|
hasher.combine("notificationSettings")
|
||||||
|
case .ZapSettings(_):
|
||||||
|
hasher.combine("zapSettings")
|
||||||
|
case .TranslationSettings(_):
|
||||||
|
hasher.combine("translationSettings")
|
||||||
|
case .SearchSettings(_):
|
||||||
|
hasher.combine("searchSettings")
|
||||||
|
case .Thread(let threadModel):
|
||||||
|
hasher.combine("thread")
|
||||||
|
hasher.combine(threadModel.event.id)
|
||||||
|
case .Reposts(let reposts):
|
||||||
|
hasher.combine("reposts")
|
||||||
|
hasher.combine(reposts.target)
|
||||||
|
case .Zaps(let target):
|
||||||
|
hasher.combine("zaps")
|
||||||
|
hasher.combine(target.id)
|
||||||
|
hasher.combine(target.pubkey)
|
||||||
|
case .Reactions(let reactions):
|
||||||
|
hasher.combine("reactions")
|
||||||
|
hasher.combine(reactions.target)
|
||||||
|
case .Search(let search):
|
||||||
|
hasher.combine("search")
|
||||||
|
hasher.combine(search.sub_id)
|
||||||
|
hasher.combine(search.profiles_subid)
|
||||||
|
case .EULA:
|
||||||
|
hasher.combine("eula")
|
||||||
|
case .Login:
|
||||||
|
hasher.combine("login")
|
||||||
|
case .CreateAccount:
|
||||||
|
hasher.combine("createAccount")
|
||||||
|
case .SaveKeys(let account):
|
||||||
|
hasher.combine("saveKeys")
|
||||||
|
hasher.combine(account.pubkey)
|
||||||
|
case .Wallet(_):
|
||||||
|
hasher.combine("wallet")
|
||||||
|
case .WalletScanner(_):
|
||||||
|
hasher.combine("walletScanner")
|
||||||
|
case .FollowersYouKnow(let friendedFollowers):
|
||||||
|
hasher.combine("followersYouKnow")
|
||||||
|
hasher.combine(friendedFollowers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NavigationCoordinator: ObservableObject {
|
||||||
|
@Published var path = [Route]()
|
||||||
|
|
||||||
|
func push(route: Route) {
|
||||||
|
path.append(route)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popToRoot() {
|
||||||
|
path = []
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ struct EventDetailBar: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
if bar.boosts > 0 {
|
if bar.boosts > 0 {
|
||||||
NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) {
|
NavigationLink(value: Route.Reposts(reposts: RepostsModel(state: state, target: target))) {
|
||||||
let noun = Text(verbatim: repostsCountString(bar.boosts)).foregroundColor(.gray)
|
let noun = Text(verbatim: repostsCountString(bar.boosts)).foregroundColor(.gray)
|
||||||
Text("\(Text(verbatim: bar.boosts.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
|
Text("\(Text(verbatim: bar.boosts.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ struct EventDetailBar: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if bar.likes > 0 && !state.settings.onlyzaps_mode {
|
if bar.likes > 0 && !state.settings.onlyzaps_mode {
|
||||||
NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) {
|
NavigationLink(value: Route.Reactions(reactions: ReactionsModel(state: state, target: target))) {
|
||||||
let noun = Text(verbatim: reactionsCountString(bar.likes)).foregroundColor(.gray)
|
let noun = Text(verbatim: reactionsCountString(bar.likes)).foregroundColor(.gray)
|
||||||
Text("\(Text(verbatim: bar.likes.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.")
|
Text("\(Text(verbatim: bar.likes.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.")
|
||||||
}
|
}
|
||||||
@@ -41,8 +41,7 @@ struct EventDetailBar: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if bar.zaps > 0 {
|
if bar.zaps > 0 {
|
||||||
let dst = ZapsView(state: state, target: .note(id: target, author: target_pk))
|
NavigationLink(value: Route.Zaps(target: .note(id: target, author: target_pk))) {
|
||||||
NavigationLink(destination: dst) {
|
|
||||||
let noun = Text(verbatim: zapsCountString(bar.zaps)).foregroundColor(.gray)
|
let noun = Text(verbatim: zapsCountString(bar.zaps)).foregroundColor(.gray)
|
||||||
Text("\(Text(verbatim: bar.zaps.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.")
|
Text("\(Text(verbatim: bar.zaps.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ struct BookmarksView: View {
|
|||||||
@State private var clearAllAlert: Bool = false
|
@State private var clearAllAlert: Bool = false
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@ObservedObject var manager: BookmarksManager
|
@ObservedObject var manager: BookmarksManager
|
||||||
|
|
||||||
init(state: DamusState) {
|
init(state: DamusState) {
|
||||||
@@ -38,6 +39,7 @@ struct BookmarksView: View {
|
|||||||
} else {
|
} else {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
InnerTimelineView(events: EventHolder(events: bookmarks, incoming: []), damus: state, filter: noneFilter)
|
InnerTimelineView(events: EventHolder(events: bookmarks, incoming: []), damus: state, filter: noneFilter)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,32 +36,31 @@ struct ConfigView: View {
|
|||||||
ZStack(alignment: .leading) {
|
ZStack(alignment: .leading) {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
NavigationLink(destination: KeySettingsView(keypair: state.keypair)) {
|
NavigationLink(value: Route.KeySettings(keypair: state.keypair)) {
|
||||||
IconLabel(NSLocalizedString("Keys", comment: "Settings section for managing keys"), img_name: "key", color: .purple)
|
IconLabel(NSLocalizedString("Keys", comment: "Settings section for managing keys"), img_name: "key", color: .purple)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: AppearanceSettingsView(settings: settings)) {
|
NavigationLink(value: Route.AppearanceSettings(settings: settings)) {
|
||||||
IconLabel(NSLocalizedString("Appearance", comment: "Section header for text and appearance settings"), img_name: "eye", color: .red)
|
IconLabel(NSLocalizedString("Appearance", comment: "Section header for text and appearance settings"), img_name: "eye", color: .red)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: SearchSettingsView(settings: settings)) {
|
NavigationLink(value: Route.SearchSettings(settings: settings)) {
|
||||||
IconLabel(NSLocalizedString("Search/Universe", comment: "Section header for search/universe settings"), img_name: "magnifyingglass", color: .red)
|
IconLabel(NSLocalizedString("Search/Universe", comment: "Section header for search/universe settings"), img_name: "magnifyingglass", color: .red)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: NotificationSettingsView(settings: settings)) {
|
NavigationLink(value: Route.NotificationSettings(settings: settings)) {
|
||||||
IconLabel(NSLocalizedString("Notifications", comment: "Section header for Damus notifications"), img_name: "notification-bell-on", color: .blue)
|
IconLabel(NSLocalizedString("Notifications", comment: "Section header for Damus notifications"), img_name: "notification-bell-on", color: .blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: ZapSettingsView(settings: settings)) {
|
NavigationLink(value: Route.ZapSettings(settings: settings)) {
|
||||||
IconLabel(NSLocalizedString("Zaps", comment: "Section header for zap settings"), img_name: "zap.fill", color: .orange)
|
IconLabel(NSLocalizedString("Zaps", comment: "Section header for zap settings"), img_name: "zap.fill", color: .orange)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: TranslationSettingsView(settings: settings)) {
|
NavigationLink(value: Route.TranslationSettings(settings: settings)) {
|
||||||
IconLabel(NSLocalizedString("Translation", comment: "Section header for text and appearance settings"), img_name: "globe", color: .green)
|
IconLabel(NSLocalizedString("Translation", comment: "Section header for text and appearance settings"), img_name: "globe", color: .green)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Section(NSLocalizedString("Sign Out", comment: "Section title for signing out")) {
|
Section(NSLocalizedString("Sign Out", comment: "Section title for signing out")) {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
if state.keypair.privkey == nil {
|
if state.keypair.privkey == nil {
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ import SwiftUI
|
|||||||
struct CreateAccountView: View {
|
struct CreateAccountView: View {
|
||||||
@StateObject var account: CreateAccountModel = CreateAccountModel()
|
@StateObject var account: CreateAccountModel = CreateAccountModel()
|
||||||
@StateObject var profileUploadViewModel = ProfileUploadingViewModel()
|
@StateObject var profileUploadViewModel = ProfileUploadingViewModel()
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@State var is_done: Bool = false
|
|
||||||
|
|
||||||
func SignupForm<FormContent: View>(@ViewBuilder content: () -> FormContent) -> some View {
|
func SignupForm<FormContent: View>(@ViewBuilder content: () -> FormContent) -> some View {
|
||||||
return VStack(alignment: .leading, spacing: 10.0, content: content)
|
return VStack(alignment: .leading, spacing: 10.0, content: content)
|
||||||
@@ -25,10 +24,6 @@ struct CreateAccountView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
NavigationLink(destination: SaveKeysView(account: account), isActive: $is_done) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
ProfilePictureSelector(pubkey: account.pubkey, viewModel: profileUploadViewModel, callback: uploadedProfilePicture(image_url:))
|
ProfilePictureSelector(pubkey: account.pubkey, viewModel: profileUploadViewModel, callback: uploadedProfilePicture(image_url:))
|
||||||
@@ -63,7 +58,7 @@ struct CreateAccountView: View {
|
|||||||
.padding(.top, 10)
|
.padding(.top, 10)
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.is_done = true
|
navigationCoordinator.push(route: Route.SaveKeys(account: account))
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Create account now", comment: "Button to create account.")
|
Text("Create account now", comment: "Button to create account.")
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ struct DMChatView: View, KeyboardReadable {
|
|||||||
|
|
||||||
var Header: some View {
|
var Header: some View {
|
||||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
let profile = damus_state.profiles.lookup(id: pubkey)
|
||||||
let profile_page = ProfileView(damus_state: damus_state, pubkey: pubkey)
|
return NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
|
||||||
return NavigationLink(destination: profile_page) {
|
|
||||||
HStack {
|
HStack {
|
||||||
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,10 @@ struct DirectMessagesView: View {
|
|||||||
@ObservedObject var model: DirectMessagesModel
|
@ObservedObject var model: DirectMessagesModel
|
||||||
@ObservedObject var settings: UserSettingsStore
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
func MainContent(requests: Bool) -> some View {
|
func MainContent(requests: Bool) -> some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
let chat = DMChatView(damus_state: damus_state, dms: model.active_model)
|
|
||||||
NavigationLink(destination: chat, isActive: $model.open_dm) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
LazyVStack(spacing: 0) {
|
LazyVStack(spacing: 0) {
|
||||||
if model.dms.isEmpty, !model.loading {
|
if model.dms.isEmpty, !model.loading {
|
||||||
EmptyTimelineView()
|
EmptyTimelineView()
|
||||||
@@ -54,7 +52,8 @@ struct DirectMessagesView: View {
|
|||||||
if ok, let ev = model.events.last {
|
if ok, let ev = model.events.last {
|
||||||
EventView(damus: damus_state, event: ev, pubkey: model.pubkey, options: options)
|
EventView(damus: damus_state, event: ev, pubkey: model.pubkey, options: options)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
self.model.open_dm_by_model(model)
|
self.model.set_active_dm_model(model)
|
||||||
|
navigationCoordinator.push(route: Route.DMChat(dms: self.model.active_model))
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|||||||
@@ -56,18 +56,13 @@ By using our Application, you signify your acceptance of this EULA. If you do no
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
struct EULAView: View {
|
struct EULAView: View {
|
||||||
@State private var login = false
|
|
||||||
@State var accepted = false
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
NavigationLink(destination: LoginView(accepted: $accepted), isActive: $login) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(Markdown.parse(content: eula))
|
Text(Markdown.parse(content: eula))
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
@@ -96,8 +91,7 @@ struct EULAView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
accepted = true
|
navigationCoordinator.push(route: Route.Login)
|
||||||
login.toggle()
|
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Accept", comment: "Button to accept the end user license agreement before being allowed into the app.")
|
Text("Accept", comment: "Button to accept the end user license agreement before being allowed into the app.")
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ struct BuilderEventView: View {
|
|||||||
if let event {
|
if let event {
|
||||||
let ev = event.get_inner_event(cache: damus.events) ?? event
|
let ev = event.get_inner_event(cache: damus.events) ?? event
|
||||||
let thread = ThreadModel(event: ev, damus_state: damus)
|
let thread = ThreadModel(event: ev, damus_state: damus)
|
||||||
let dest = ThreadView(state: damus, thread: thread)
|
NavigationLink(value: Route.Thread(thread: thread)) {
|
||||||
NavigationLink(destination: dest) {
|
|
||||||
EventView(damus: damus, event: event, options: .embedded)
|
EventView(damus: damus, event: event, options: .embedded)
|
||||||
.padding([.top, .bottom], 8)
|
.padding([.top, .bottom], 8)
|
||||||
}.buttonStyle(.plain)
|
}.buttonStyle(.plain)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct EventProfile: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
VStack {
|
VStack {
|
||||||
NavigationLink(destination: ProfileView(damus_state: damus_state, pubkey: pubkey)) {
|
NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
|
||||||
ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles, disable_animation: disable_animation)
|
ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles, disable_animation: disable_animation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,16 @@ import SwiftUI
|
|||||||
struct FollowUserView: View {
|
struct FollowUserView: View {
|
||||||
let target: FollowTarget
|
let target: FollowTarget
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
static let markdown = Markdown()
|
static let markdown = Markdown()
|
||||||
@State var navigating: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let dest = ProfileView(damus_state: damus_state, pubkey: target.pubkey)
|
|
||||||
NavigationLink(destination: dest, isActive: $navigating) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
UserViewRow(damus_state: damus_state, pubkey: target.pubkey)
|
UserViewRow(damus_state: damus_state, pubkey: target.pubkey)
|
||||||
|
.onTapGesture {
|
||||||
|
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: target.pubkey))
|
||||||
|
}
|
||||||
|
|
||||||
FollowButtonView(target: target, follows_you: false, follow_state: damus_state.contacts.follow_state(target.pubkey))
|
FollowButtonView(target: target, follows_you: false, follow_state: damus_state.contacts.follow_state(target.pubkey))
|
||||||
}
|
}
|
||||||
@@ -52,12 +50,14 @@ struct FollowersView: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
@EnvironmentObject var followers: FollowersModel
|
@EnvironmentObject var followers: FollowersModel
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack(alignment: .leading) {
|
LazyVStack(alignment: .leading) {
|
||||||
ForEach(followers.contacts ?? [], id: \.self) { pk in
|
ForEach(followers.contacts ?? [], id: \.self) { pk in
|
||||||
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@@ -77,11 +77,14 @@ struct FollowingView: View {
|
|||||||
|
|
||||||
let following: FollowingModel
|
let following: FollowingModel
|
||||||
|
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack(alignment: .leading) {
|
LazyVStack(alignment: .leading) {
|
||||||
ForEach(following.contacts.reversed(), id: \.self) { pk in
|
ForEach(following.contacts.reversed(), id: \.self) { pk in
|
||||||
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ enum ParsedKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct LoginView: View {
|
struct LoginView: View {
|
||||||
@State private var create_account = false
|
|
||||||
@State var key: String = ""
|
@State var key: String = ""
|
||||||
@State var is_pubkey: Bool = false
|
@State var is_pubkey: Bool = false
|
||||||
@State var error: String? = nil
|
@State var error: String? = nil
|
||||||
@State private var credential_handler = CredentialHandler()
|
@State private var credential_handler = CredentialHandler()
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@Binding var accepted: Bool
|
|
||||||
|
|
||||||
func get_error(parsed_key: ParsedKey?) -> String? {
|
func get_error(parsed_key: ParsedKey?) -> String? {
|
||||||
if self.error != nil {
|
if self.error != nil {
|
||||||
@@ -55,12 +53,6 @@ struct LoginView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
if accepted {
|
|
||||||
NavigationLink(destination: CreateAccountView(), isActive: $create_account) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
SignInHeader()
|
SignInHeader()
|
||||||
.padding(.top, 100)
|
.padding(.top, 100)
|
||||||
@@ -107,7 +99,8 @@ struct LoginView: View {
|
|||||||
.padding(.top, 10)
|
.padding(.top, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateAccountPrompt(create_account: $create_account)
|
CreateAccountPrompt()
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.padding(.top, 10)
|
.padding(.top, 10)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -337,14 +330,14 @@ struct SignInEntry: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CreateAccountPrompt: View {
|
struct CreateAccountPrompt: View {
|
||||||
@Binding var create_account: Bool
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Text("New to Nostr?", comment: "Ask the user if they are new to Nostr")
|
Text("New to Nostr?", comment: "Ask the user if they are new to Nostr")
|
||||||
.foregroundColor(Color("DamusMediumGrey"))
|
.foregroundColor(Color("DamusMediumGrey"))
|
||||||
|
|
||||||
Button(NSLocalizedString("Create account", comment: "Button to navigate to create account view.")) {
|
Button(NSLocalizedString("Create account", comment: "Button to navigate to create account view.")) {
|
||||||
create_account.toggle()
|
navigationCoordinator.push(route: Route.CreateAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -358,8 +351,8 @@ struct LoginView_Previews: PreviewProvider {
|
|||||||
let pubkey = "npub18m76awca3y37hkvuneavuw6pjj4525fw90necxmadrvjg0sdy6qsngq955"
|
let pubkey = "npub18m76awca3y37hkvuneavuw6pjj4525fw90necxmadrvjg0sdy6qsngq955"
|
||||||
let bech32_pubkey = "KeyInput"
|
let bech32_pubkey = "KeyInput"
|
||||||
Group {
|
Group {
|
||||||
LoginView(key: pubkey, accepted: .constant(true))
|
LoginView(key: pubkey)
|
||||||
LoginView(key: bech32_pubkey, accepted: .constant(true))
|
LoginView(key: bech32_pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,6 +193,8 @@ struct EventGroupView: View {
|
|||||||
let event: NostrEvent?
|
let event: NostrEvent?
|
||||||
let group: EventGroupType
|
let group: EventGroupType
|
||||||
|
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
func GroupDescription(_ pubkeys: [String]) -> some View {
|
func GroupDescription(_ pubkeys: [String]) -> some View {
|
||||||
Text(verbatim: "\(reacting_to_text(profiles: state.profiles, our_pubkey: state.pubkey, group: group, ev: event, pubkeys: pubkeys))")
|
Text(verbatim: "\(reacting_to_text(profiles: state.profiles, our_pubkey: state.pubkey, group: group, ev: event, pubkeys: pubkeys))")
|
||||||
}
|
}
|
||||||
@@ -237,11 +239,11 @@ struct EventGroupView: View {
|
|||||||
let unique_pubkeys = event_group_unique_pubkeys(profiles: state.profiles, group: group)
|
let unique_pubkeys = event_group_unique_pubkeys(profiles: state.profiles, group: group)
|
||||||
|
|
||||||
ProfilePicturesView(state: state, pubkeys: unique_pubkeys)
|
ProfilePicturesView(state: state, pubkeys: unique_pubkeys)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
if let event {
|
if let event {
|
||||||
let thread = ThreadModel(event: event, damus_state: state)
|
let thread = ThreadModel(event: event, damus_state: state)
|
||||||
let dest = ThreadView(state: state, thread: thread)
|
NavigationLink(value: Route.Thread(thread: thread)) {
|
||||||
NavigationLink(destination: dest) {
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
GroupDescription(unique_pubkeys)
|
GroupDescription(unique_pubkeys)
|
||||||
EventBody(damus_state: state, event: event, size: .normal, options: [.truncate_content])
|
EventBody(damus_state: state, event: event, size: .normal, options: [.truncate_content])
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ struct NotificationItemView: View {
|
|||||||
let state: DamusState
|
let state: DamusState
|
||||||
let item: NotificationItem
|
let item: NotificationItem
|
||||||
|
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var show_item: ShowItem {
|
var show_item: ShowItem {
|
||||||
notification_item_event(events: state.events, notif: item)
|
notification_item_event(events: state.events, notif: item)
|
||||||
}
|
}
|
||||||
@@ -48,18 +50,22 @@ struct NotificationItemView: View {
|
|||||||
switch item {
|
switch item {
|
||||||
case .repost(_, let evgrp):
|
case .repost(_, let evgrp):
|
||||||
EventGroupView(state: state, event: ev, group: .repost(evgrp))
|
EventGroupView(state: state, event: ev, group: .repost(evgrp))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .event_zap(_, let zapgrp):
|
case .event_zap(_, let zapgrp):
|
||||||
EventGroupView(state: state, event: ev, group: .zap(zapgrp))
|
EventGroupView(state: state, event: ev, group: .zap(zapgrp))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .profile_zap(let grp):
|
case .profile_zap(let grp):
|
||||||
EventGroupView(state: state, event: nil, group: .profile_zap(grp))
|
EventGroupView(state: state, event: nil, group: .profile_zap(grp))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .reaction(_, let evgrp):
|
case .reaction(_, let evgrp):
|
||||||
EventGroupView(state: state, event: ev, group: .reaction(evgrp))
|
EventGroupView(state: state, event: ev, group: .reaction(evgrp))
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .reply(let ev):
|
case .reply(let ev):
|
||||||
NavigationLink(destination: ThreadView(state: state, thread: ThreadModel(event: ev, damus_state: state))) {
|
NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) {
|
||||||
EventView(damus: state, event: ev, options: options)
|
EventView(damus: state, event: ev, options: options)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ struct NotificationsView: View {
|
|||||||
@SceneStorage("NotificationsView.filter_state") var filter_state: NotificationFilterState = .all
|
@SceneStorage("NotificationsView.filter_state") var filter_state: NotificationFilterState = .all
|
||||||
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var mystery: some View {
|
var mystery: some View {
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
@@ -173,6 +174,7 @@ struct NotificationsView: View {
|
|||||||
.frame(height: 5)
|
.frame(height: 5)
|
||||||
ForEach(filter.filter(contacts: state.contacts, items: notifications.notifications), id: \.id) { item in
|
ForEach(filter.filter(contacts: state.contacts, items: notifications.notifications), id: \.id) { item in
|
||||||
NotificationItemView(state: state, item: item)
|
NotificationItemView(state: state, item: item)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(GeometryReader { proxy -> Color in
|
.background(GeometryReader { proxy -> Color in
|
||||||
|
|||||||
@@ -11,19 +11,14 @@ struct ProfilePicturesView: View {
|
|||||||
let state: DamusState
|
let state: DamusState
|
||||||
let pubkeys: [String]
|
let pubkeys: [String]
|
||||||
|
|
||||||
@State var nav_target: String? = nil
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@State var navigating: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationLink(destination: ProfileView(damus_state: state, pubkey: nav_target ?? ""), isActive: $navigating) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
HStack {
|
HStack {
|
||||||
ForEach(pubkeys.prefix(8), id: \.self) { pubkey in
|
ForEach(pubkeys.prefix(8), id: \.self) { pubkey in
|
||||||
ProfilePicView(pubkey: pubkey, size: 32.0, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: 32.0, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
nav_target = pubkey
|
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: pubkey))
|
||||||
navigating = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ struct MaybeAnonPfpView: View {
|
|||||||
.font(.largeTitle)
|
.font(.largeTitle)
|
||||||
.frame(width: size, height: size)
|
.frame(width: size, height: size)
|
||||||
} else {
|
} else {
|
||||||
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pubkey)) {
|
NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
|
||||||
ProfilePicView(pubkey: pubkey, size: size, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation)
|
ProfilePicView(pubkey: pubkey, size: size, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ struct EditButton: View {
|
|||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationLink(destination: EditMetadataView(damus_state: damus_state)) {
|
NavigationLink(value: Route.EditMetadata) {
|
||||||
Text("Edit", comment: "Button to edit user's profile.")
|
Text("Edit", comment: "Button to edit user's profile.")
|
||||||
.frame(height: 30)
|
.frame(height: 30)
|
||||||
.padding(.horizontal,25)
|
.padding(.horizontal,25)
|
||||||
@@ -132,6 +132,8 @@ struct ProfileView: View {
|
|||||||
@StateObject var followers: FollowersModel
|
@StateObject var followers: FollowersModel
|
||||||
@StateObject var zap_button_model: ZapButtonModel = ZapButtonModel()
|
@StateObject var zap_button_model: ZapButtonModel = ZapButtonModel()
|
||||||
|
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) {
|
init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
self._profile = StateObject(wrappedValue: profile)
|
self._profile = StateObject(wrappedValue: profile)
|
||||||
@@ -300,8 +302,7 @@ struct ProfileView: View {
|
|||||||
|
|
||||||
var dmButton: some View {
|
var dmButton: some View {
|
||||||
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
|
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
|
||||||
let dmview = DMChatView(damus_state: damus_state, dms: dm_model)
|
return NavigationLink(value: Route.DMChat(dms: dm_model)) {
|
||||||
return NavigationLink(destination: dmview) {
|
|
||||||
Image("messages")
|
Image("messages")
|
||||||
.profile_button_style(scheme: colorScheme)
|
.profile_button_style(scheme: colorScheme)
|
||||||
}
|
}
|
||||||
@@ -325,7 +326,7 @@ struct ProfileView: View {
|
|||||||
follow_state: damus_state.contacts.follow_state(profile.pubkey)
|
follow_state: damus_state.contacts.follow_state(profile.pubkey)
|
||||||
)
|
)
|
||||||
} else if damus_state.keypair.privkey != nil {
|
} else if damus_state.keypair.privkey != nil {
|
||||||
NavigationLink(destination: EditMetadataView(damus_state: damus_state)) {
|
NavigationLink(value: Route.EditMetadata) {
|
||||||
EditButton(damus_state: damus_state)
|
EditButton(damus_state: damus_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,7 +405,7 @@ struct ProfileView: View {
|
|||||||
if let contact = profile.contacts {
|
if let contact = profile.contacts {
|
||||||
let contacts = contact.referenced_pubkeys.map { $0.ref_id }
|
let contacts = contact.referenced_pubkeys.map { $0.ref_id }
|
||||||
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
|
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
|
||||||
NavigationLink(destination: FollowingView(damus_state: damus_state, following: following_model)) {
|
NavigationLink(value: Route.Following(following: following_model)) {
|
||||||
HStack {
|
HStack {
|
||||||
let noun_text = Text(verbatim: "\(followingCountString(profile.following))").font(.subheadline).foregroundColor(.gray)
|
let noun_text = Text(verbatim: "\(followingCountString(profile.following))").font(.subheadline).foregroundColor(.gray)
|
||||||
Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.")
|
Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.")
|
||||||
@@ -412,10 +413,9 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
let fview = FollowersView(damus_state: damus_state)
|
|
||||||
.environmentObject(followers)
|
|
||||||
if followers.contacts != nil {
|
if followers.contacts != nil {
|
||||||
NavigationLink(destination: fview) {
|
NavigationLink(value: Route.Followers(environmentObject: followers)) {
|
||||||
followersCount
|
followersCount
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
@@ -433,12 +433,12 @@ struct ProfileView: View {
|
|||||||
let noun_text = Text(verbatim: relaysCountString(relays.keys.count)).font(.subheadline).foregroundColor(.gray)
|
let noun_text = Text(verbatim: relaysCountString(relays.keys.count)).font(.subheadline).foregroundColor(.gray)
|
||||||
let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
|
let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
|
||||||
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
|
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
|
||||||
NavigationLink(destination: RelayConfigView(state: damus_state)) {
|
NavigationLink(value: Route.RelayConfig) {
|
||||||
relay_text
|
relay_text
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
} else {
|
} else {
|
||||||
NavigationLink(destination: UserRelaysView(state: damus_state, relays: Array(relays.keys).sorted())) {
|
NavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) {
|
||||||
relay_text
|
relay_text
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
@@ -451,7 +451,7 @@ struct ProfileView: View {
|
|||||||
if !friended_followers.isEmpty {
|
if !friended_followers.isEmpty {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
NavigationLink(destination: FollowersYouKnowView(damus_state: damus_state, friended_followers: friended_followers)) {
|
NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers)) {
|
||||||
HStack {
|
HStack {
|
||||||
CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3)
|
CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3)
|
||||||
Text(followedByString(friended_followers, profiles: damus_state.profiles))
|
Text(followedByString(friended_followers, profiles: damus_state.profiles))
|
||||||
@@ -521,6 +521,7 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $show_qr_code) {
|
.fullScreenCover(isPresented: $show_qr_code) {
|
||||||
QRCodeView(damus_state: damus_state, pubkey: profile.pubkey)
|
QRCodeView(damus_state: damus_state, pubkey: profile.pubkey)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
if damus_state.is_privkey_user {
|
if damus_state.is_privkey_user {
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ struct QRCodeView: View {
|
|||||||
@State var pubkey: String
|
@State var pubkey: String
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentationMode
|
@Environment(\.presentationMode) var presentationMode
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
@State private var selectedTab = 0
|
@State private var selectedTab = 0
|
||||||
|
|
||||||
@State var scanResult: ProfileScanResult? = nil
|
@State var scanResult: ProfileScanResult? = nil
|
||||||
|
|
||||||
@State var showProfileView: Bool = false
|
|
||||||
@State var profile: Profile? = nil
|
@State var profile: Profile? = nil
|
||||||
@State var error: String? = nil
|
@State var error: String? = nil
|
||||||
|
|
||||||
@@ -209,13 +209,6 @@ struct QRCodeView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if let scanResult {
|
|
||||||
let dst = ProfileView(damus_state: damus_state, pubkey: scanResult.pubkey)
|
|
||||||
NavigationLink(destination: dst, isActive: $showProfileView) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
@@ -271,9 +264,10 @@ struct QRCodeView: View {
|
|||||||
|
|
||||||
func show_profile_after_delay() {
|
func show_profile_after_delay() {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
|
||||||
showProfileView = true
|
if let scanResult {
|
||||||
|
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: scanResult.pubkey))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func cameraAnimate(completion: @escaping () -> Void) {
|
func cameraAnimate(completion: @escaping () -> Void) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import SwiftUI
|
|||||||
struct ReactionView: View {
|
struct ReactionView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let reaction: NostrEvent
|
let reaction: NostrEvent
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var content: String {
|
var content: String {
|
||||||
return to_reaction_emoji(ev: reaction) ?? ""
|
return to_reaction_emoji(ev: reaction) ?? ""
|
||||||
@@ -22,6 +23,7 @@ struct ReactionView: View {
|
|||||||
.frame(width: 50, height: 50)
|
.frame(width: 50, height: 50)
|
||||||
|
|
||||||
FollowUserView(target: .pubkey(reaction.pubkey), damus_state: damus_state)
|
FollowUserView(target: .pubkey(reaction.pubkey), damus_state: damus_state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import SwiftUI
|
|||||||
struct ReactionsView: View {
|
struct ReactionsView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@StateObject var model: ReactionsModel
|
@StateObject var model: ReactionsModel
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ struct ReactionsView: View {
|
|||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(model.events, id: \.id) { ev in
|
ForEach(model.events, id: \.id) { ev in
|
||||||
ReactionView(damus_state: damus_state, reaction: ev)
|
ReactionView(damus_state: damus_state, reaction: ev)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ struct RecommendedRelayView: View {
|
|||||||
Text(relay).layoutPriority(1)
|
Text(relay).layoutPriority(1)
|
||||||
|
|
||||||
if let meta = damus.relay_metadata.lookup(relay_id: relay) {
|
if let meta = damus.relay_metadata.lookup(relay_id: relay) {
|
||||||
NavigationLink ( destination:
|
NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta)){
|
||||||
RelayDetailView(state: damus, relay: relay, nip11: meta)
|
|
||||||
){
|
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
.opacity(0.0)
|
.opacity(0.0)
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ struct RelayDetailView: View {
|
|||||||
|
|
||||||
if let pubkey = nip11.pubkey {
|
if let pubkey = nip11.pubkey {
|
||||||
Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) {
|
Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) {
|
||||||
|
NavigationLink(value: Route.ProfileByKey(pubkey: pubkey), label: {
|
||||||
UserViewRow(damus_state: state, pubkey: pubkey)
|
UserViewRow(damus_state: state, pubkey: pubkey)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let relay_connection {
|
if let relay_connection {
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ struct RelayView: View {
|
|||||||
if let meta = state.relay_metadata.lookup(relay_id: relay) {
|
if let meta = state.relay_metadata.lookup(relay_id: relay) {
|
||||||
Text(relay)
|
Text(relay)
|
||||||
.background(
|
.background(
|
||||||
NavigationLink("", destination: RelayDetailView(state: state, relay: relay, nip11: meta)).opacity(0.0)
|
NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta), label: {
|
||||||
.disabled(showActionButtons)
|
EmptyView()
|
||||||
|
}).opacity(0.0).disabled(showActionButtons)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct SignalView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
if signal.signal != signal.max_signal {
|
if signal.signal != signal.max_signal {
|
||||||
NavigationLink(destination: RelayConfigView(state: state)) {
|
NavigationLink(value: Route.RelayConfig) {
|
||||||
Text("\(signal.signal)/\(signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.")
|
Text("\(signal.signal)/\(signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.")
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import SwiftUI
|
|||||||
struct RepostView: View {
|
struct RepostView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let repost: NostrEvent
|
let repost: NostrEvent
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
FollowUserView(target: .pubkey(repost.pubkey), damus_state: damus_state)
|
FollowUserView(target: .pubkey(repost.pubkey), damus_state: damus_state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ struct RepostedEvent: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
let prof = damus.profiles.lookup(id: event.pubkey)
|
let prof = damus.profiles.lookup(id: event.pubkey)
|
||||||
let booster_profile = ProfileView(damus_state: damus, pubkey: event.pubkey)
|
|
||||||
|
|
||||||
NavigationLink(destination: booster_profile) {
|
NavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) {
|
||||||
Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
|
Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import SwiftUI
|
|||||||
struct RepostsView: View {
|
struct RepostsView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@StateObject var model: RepostsModel
|
@StateObject var model: RepostsModel
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(model.events, id: \.id) { ev in
|
ForEach(model.events, id: \.id) { ev in
|
||||||
RepostView(damus_state: damus_state, repost: ev)
|
RepostView(damus_state: damus_state, repost: ev)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct SearchingEventView: View {
|
|||||||
let state: DamusState
|
let state: DamusState
|
||||||
let evid: String
|
let evid: String
|
||||||
let search_type: SearchType
|
let search_type: SearchType
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
@State var search_state: SearchState = .searching
|
@State var search_state: SearchState = .searching
|
||||||
|
|
||||||
@@ -100,15 +101,14 @@ struct SearchingEventView: View {
|
|||||||
.progressViewStyle(.circular)
|
.progressViewStyle(.circular)
|
||||||
}
|
}
|
||||||
case .found(let ev):
|
case .found(let ev):
|
||||||
NavigationLink(destination: ThreadView(state: state, thread: ThreadModel(event: ev, damus_state: state))) {
|
NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) {
|
||||||
|
|
||||||
EventView(damus: state, event: ev)
|
EventView(damus: state, event: ev)
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
case .found_profile(let pk):
|
case .found_profile(let pk):
|
||||||
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pk)) {
|
NavigationLink(value: Route.ProfileByKey(pubkey: pk)) {
|
||||||
|
|
||||||
FollowUserView(target: .pubkey(pk), damus_state: state)
|
FollowUserView(target: .pubkey(pk), damus_state: state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
case .not_found:
|
case .not_found:
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ struct SearchHomeView: View {
|
|||||||
@StateObject var model: SearchHomeModel
|
@StateObject var model: SearchHomeModel
|
||||||
@State var search: String = ""
|
@State var search: String = ""
|
||||||
@FocusState private var isFocused: Bool
|
@FocusState private var isFocused: Bool
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
let preferredLanguages = Set(Locale.preferredLanguages.map { localeToLanguage($0) })
|
let preferredLanguages = Set(Locale.preferredLanguages.map { localeToLanguage($0) })
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ struct SearchHomeView: View {
|
|||||||
return preferredLanguages.contains(note_lang)
|
return preferredLanguages.contains(note_lang)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.refreshable {
|
.refreshable {
|
||||||
// Fetch new information by unsubscribing and resubscribing to the relay
|
// Fetch new information by unsubscribing and resubscribing to the relay
|
||||||
model.unsubscribe()
|
model.unsubscribe()
|
||||||
@@ -76,6 +78,7 @@ struct SearchHomeView: View {
|
|||||||
|
|
||||||
var SearchContent: some View {
|
var SearchContent: some View {
|
||||||
SearchResultsView(damus_state: damus_state, search: $search)
|
SearchResultsView(damus_state: damus_state, search: $search)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.refreshable {
|
.refreshable {
|
||||||
// Fetch new information by unsubscribing and resubscribing to the relay
|
// Fetch new information by unsubscribing and resubscribing to the relay
|
||||||
model.unsubscribe()
|
model.unsubscribe()
|
||||||
|
|||||||
@@ -37,15 +37,16 @@ enum Search: Identifiable {
|
|||||||
struct InnerSearchResults: View {
|
struct InnerSearchResults: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let search: Search?
|
let search: Search?
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
func ProfileSearchResult(pk: String) -> some View {
|
func ProfileSearchResult(pk: String) -> some View {
|
||||||
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HashtagSearch(_ ht: String) -> some View {
|
func HashtagSearch(_ ht: String) -> some View {
|
||||||
let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
|
let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
|
||||||
let dst = SearchView(appstate: damus_state, search: search_model)
|
return NavigationLink(value: Route.Search(search: search_model)) {
|
||||||
return NavigationLink(destination: dst) {
|
|
||||||
Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
|
Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,6 +70,7 @@ struct InnerSearchResults: View {
|
|||||||
|
|
||||||
case .nip05(let addr):
|
case .nip05(let addr):
|
||||||
SearchingEventView(state: damus_state, evid: addr, search_type: .nip05)
|
SearchingEventView(state: damus_state, evid: addr, search_type: .nip05)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
|
|
||||||
case .profile(let prof):
|
case .profile(let prof):
|
||||||
let decoded = try? bech32_decode(prof)
|
let decoded = try? bech32_decode(prof)
|
||||||
@@ -107,10 +109,12 @@ struct SearchResultsView: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
@State var result: Search? = nil
|
@State var result: Search? = nil
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
InnerSearchResults(damus_state: damus_state, search: result)
|
InnerSearchResults(damus_state: damus_state, search: result)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.frame(maxHeight: .infinity)
|
.frame(maxHeight: .infinity)
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ struct SearchView: View {
|
|||||||
let appstate: DamusState
|
let appstate: DamusState
|
||||||
@StateObject var search: SearchModel
|
@StateObject var search: SearchModel
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineView(events: search.events, loading: $search.loading, damus: appstate, show_friend_icon: true, filter: { _ in true })
|
TimelineView(events: search.events, loading: $search.loading, damus: appstate, show_friend_icon: true, filter: { _ in true })
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.navigationBarTitle(describe_search(search.search))
|
.navigationBarTitle(describe_search(search.search))
|
||||||
.onReceive(handle_notify(.switched_timeline)) { obj in
|
.onReceive(handle_notify(.switched_timeline)) { obj in
|
||||||
dismiss()
|
dismiss()
|
||||||
|
|||||||
@@ -17,16 +17,12 @@ func hex_col(r: UInt8, g: UInt8, b: UInt8) -> Color {
|
|||||||
|
|
||||||
|
|
||||||
struct SetupView: View {
|
struct SetupView: View {
|
||||||
@State private var eula = false
|
@StateObject var navigationCoordinator: NavigationCoordinator = NavigationCoordinator()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationStack(path: $navigationCoordinator.path) {
|
||||||
ZStack {
|
ZStack {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
NavigationLink(destination: EULAView(), isActive: $eula) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Image("logo-nobg")
|
Image("logo-nobg")
|
||||||
@@ -53,7 +49,7 @@ struct SetupView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
eula.toggle()
|
navigationCoordinator.push(route: Route.EULA)
|
||||||
}) {
|
}) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Let's get started!", comment: "Button to continue to login page.")
|
Text("Let's get started!", comment: "Button to continue to login page.")
|
||||||
@@ -72,6 +68,9 @@ struct SetupView: View {
|
|||||||
.ignoresSafeArea(),
|
.ignoresSafeArea(),
|
||||||
alignment: .top
|
alignment: .top
|
||||||
)
|
)
|
||||||
|
.navigationDestination(for: Route.self) { route in
|
||||||
|
route.view(navigationCordinator: navigationCoordinator, damusState: DamusState.empty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
.navigationViewStyle(StackNavigationViewStyle())
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct SideMenuView: View {
|
|||||||
@State private var showQRCode = false
|
@State private var showQRCode = false
|
||||||
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0)
|
var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0)
|
||||||
let verticalSpacing: CGFloat = 20
|
let verticalSpacing: CGFloat = 20
|
||||||
@@ -45,11 +46,11 @@ struct SideMenuView: View {
|
|||||||
|
|
||||||
func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View {
|
func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View {
|
||||||
return VStack(spacing: verticalSpacing) {
|
return VStack(spacing: verticalSpacing) {
|
||||||
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
|
NavigationLink(value: Route.Profile(profile: profile_model, followers: followers)) {
|
||||||
navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user")
|
navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: WalletView(damus_state: damus_state, model: damus_state.wallet)) {
|
NavigationLink(value: Route.Wallet(wallet: damus_state.wallet)) {
|
||||||
navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet")
|
navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet")
|
||||||
/*
|
/*
|
||||||
HStack {
|
HStack {
|
||||||
@@ -64,19 +65,19 @@ struct SideMenuView: View {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: MutelistView(damus_state: damus_state, users: get_mutelist_users(damus_state.contacts.mutelist) )) {
|
NavigationLink(value: Route.MuteList(users: get_mutelist_users(damus_state.contacts.mutelist))) {
|
||||||
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
|
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: RelayConfigView(state: damus_state)) {
|
NavigationLink(value: Route.RelayConfig) {
|
||||||
navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays")
|
navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: BookmarksView(state: damus_state)) {
|
NavigationLink(value: Route.Bookmarks) {
|
||||||
navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark")
|
navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: ConfigView(state: damus_state)) {
|
NavigationLink(value: Route.Config) {
|
||||||
navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings")
|
navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +89,7 @@ struct SideMenuView: View {
|
|||||||
let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
|
let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
|
||||||
let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
|
let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
|
||||||
|
|
||||||
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
|
NavigationLink(value: Route.Profile(profile: profile_model, followers: followers), label: {
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ struct SideMenuView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.bottom, verticalSpacing)
|
.padding(.bottom, verticalSpacing)
|
||||||
}
|
})
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
@@ -162,6 +162,7 @@ struct SideMenuView: View {
|
|||||||
.dynamicTypeSize(.xSmall)
|
.dynamicTypeSize(.xSmall)
|
||||||
}).fullScreenCover(isPresented: $showQRCode) {
|
}).fullScreenCover(isPresented: $showQRCode) {
|
||||||
QRCodeView(damus_state: damus_state, pubkey: damus_state.pubkey)
|
QRCodeView(damus_state: damus_state, pubkey: damus_state.pubkey)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, verticalSpacing)
|
.padding(.top, verticalSpacing)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ struct InnerTimelineView: View {
|
|||||||
@ObservedObject var events: EventHolder
|
@ObservedObject var events: EventHolder
|
||||||
let state: DamusState
|
let state: DamusState
|
||||||
let filter: (NostrEvent) -> Bool
|
let filter: (NostrEvent) -> Bool
|
||||||
@State var nav_target: NostrEvent
|
|
||||||
@State var navigating: Bool = false
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
static var count: Int = 0
|
static var count: Int = 0
|
||||||
|
|
||||||
@@ -23,8 +23,6 @@ struct InnerTimelineView: View {
|
|||||||
self.filter = filter
|
self.filter = filter
|
||||||
print("rendering InnerTimelineView \(InnerTimelineView.count)")
|
print("rendering InnerTimelineView \(InnerTimelineView.count)")
|
||||||
InnerTimelineView.count += 1
|
InnerTimelineView.count += 1
|
||||||
// dummy event to avoid MaybeThreadView
|
|
||||||
self._nav_target = State(initialValue: test_event)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var event_options: EventViewOptions {
|
var event_options: EventViewOptions {
|
||||||
@@ -36,11 +34,6 @@ struct InnerTimelineView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let thread = ThreadModel(event: nav_target, damus_state: state)
|
|
||||||
let dest = ThreadView(state: state, thread: thread)
|
|
||||||
NavigationLink(destination: dest, isActive: $navigating) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
LazyVStack(spacing: 0) {
|
LazyVStack(spacing: 0) {
|
||||||
let events = self.events.events
|
let events = self.events.events
|
||||||
if events.isEmpty {
|
if events.isEmpty {
|
||||||
@@ -53,8 +46,9 @@ struct InnerTimelineView: View {
|
|||||||
let ind = tup.1
|
let ind = tup.1
|
||||||
EventView(damus: state, event: ev, options: event_options)
|
EventView(damus: state, event: ev, options: event_options)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
nav_target = ev.get_inner_event(cache: state.events) ?? ev
|
let event = ev.get_inner_event(cache: state.events) ?? ev
|
||||||
navigating = true
|
let thread = ThreadModel(event: event, damus_state: state)
|
||||||
|
navigationCoordinator.push(route: Route.Thread(thread: thread))
|
||||||
}
|
}
|
||||||
.padding(.top, 7)
|
.padding(.top, 7)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct TimelineView: View {
|
struct TimelineView: View {
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@ObservedObject var events: EventHolder
|
@ObservedObject var events: EventHolder
|
||||||
@Binding var loading: Bool
|
@Binding var loading: Bool
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ struct TimelineView: View {
|
|||||||
.frame(height: 1)
|
.frame(height: 1)
|
||||||
|
|
||||||
InnerTimelineView(events: events, damus: damus, filter: loading ? { _ in true } : filter)
|
InnerTimelineView(events: events, damus: damus, filter: loading ? { _ in true } : filter)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
.redacted(reason: loading ? .placeholder : [])
|
.redacted(reason: loading ? .placeholder : [])
|
||||||
.shimmer(loading)
|
.shimmer(loading)
|
||||||
.disabled(loading)
|
.disabled(loading)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ConnectWalletView: View {
|
struct ConnectWalletView: View {
|
||||||
@Environment(\.openURL) private var openURL
|
@Environment(\.openURL) private var openURL
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
@ObservedObject var model: WalletModel
|
@ObservedObject var model: WalletModel
|
||||||
|
|
||||||
@State var scanning: Bool = false
|
@State var scanning: Bool = false
|
||||||
@@ -64,16 +65,12 @@ struct ConnectWalletView: View {
|
|||||||
|
|
||||||
var ConnectWallet: some View {
|
var ConnectWallet: some View {
|
||||||
VStack {
|
VStack {
|
||||||
NavigationLink(destination: WalletScannerView(result: $wallet_scan_result), isActive: $scanning) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
AlbyButton() {
|
AlbyButton() {
|
||||||
openURL(URL(string:"https://nwc.getalby.com/apps/new?c=Damus")!)
|
openURL(URL(string:"https://nwc.getalby.com/apps/new?c=Damus")!)
|
||||||
}
|
}
|
||||||
|
|
||||||
BigButton(NSLocalizedString("Attach Wallet", comment: "Text for button to attach Nostr Wallet Connect lightning wallet.")) {
|
BigButton(NSLocalizedString("Attach Wallet", comment: "Text for button to attach Nostr Wallet Connect lightning wallet.")) {
|
||||||
scanning = true
|
navigationCoordinator.push(route: Route.WalletScanner(result: $wallet_scan_result))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let err = self.error {
|
if let err = self.error {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ struct WalletView: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@ObservedObject var model: WalletModel
|
@ObservedObject var model: WalletModel
|
||||||
@ObservedObject var settings: UserSettingsStore
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
|
||||||
|
|
||||||
init(damus_state: DamusState, model: WalletModel? = nil) {
|
init(damus_state: DamusState, model: WalletModel? = nil) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
@@ -156,8 +157,10 @@ struct WalletView: View {
|
|||||||
switch model.connect_state {
|
switch model.connect_state {
|
||||||
case .new:
|
case .new:
|
||||||
ConnectWalletView(model: model)
|
ConnectWalletView(model: model)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
case .none:
|
case .none:
|
||||||
ConnectWalletView(model: model)
|
ConnectWalletView(model: model)
|
||||||
|
.environmentObject(navigationCoordinator)
|
||||||
case .existing(let nwc):
|
case .existing(let nwc):
|
||||||
MainWalletView(nwc: nwc)
|
MainWalletView(nwc: nwc)
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
|
|||||||
Reference in New Issue
Block a user