nav: remove environmentObjects

environment objects are implicit arguments that cannot be checked by the
compiler. They are a common source of crashes. Use a main
NavigationCoordinator in DamusState for the core app, and pass in other
coordinators in the account setup view for the parts of the app that
don't have a DamusState.
This commit is contained in:
William Casarin
2023-06-30 09:59:58 -07:00
parent 9008c609e2
commit f702733654
29 changed files with 46 additions and 130 deletions

View File

@@ -143,7 +143,6 @@ 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)
} }
} }
} }
@@ -164,12 +163,10 @@ struct ContentView: View {
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:
@@ -177,11 +174,9 @@ 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)
@@ -282,7 +277,6 @@ 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 .navigationDestination(for: Route.self) { route in
route.view(navigationCordinator: navigationCoordinator, damusState: damus_state!) route.view(navigationCordinator: navigationCoordinator, damusState: damus_state!)
@@ -651,7 +645,8 @@ struct ContentView: View {
bootstrap_relays: bootstrap_relays, bootstrap_relays: bootstrap_relays,
replies: ReplyCounter(our_pubkey: pubkey), replies: ReplyCounter(our_pubkey: pubkey),
muted_threads: MutedThreadsManager(keypair: keypair), muted_threads: MutedThreadsManager(keypair: keypair),
wallet: WalletModel(settings: settings) wallet: WalletModel(settings: settings),
nav: self.navigationCoordinator
) )
home.damus_state = self.damus_state! home.damus_state = self.damus_state!

View File

@@ -30,6 +30,7 @@ struct DamusState {
let replies: ReplyCounter let replies: ReplyCounter
let muted_threads: MutedThreadsManager let muted_threads: MutedThreadsManager
let wallet: WalletModel let wallet: WalletModel
let nav: NavigationCoordinator
@discardableResult @discardableResult
func add_zap(zap: Zapping) -> Bool { func add_zap(zap: Zapping) -> Bool {
@@ -57,5 +58,5 @@ struct DamusState {
} }
static var empty: DamusState { static var empty: DamusState {
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts(), events: EventCache(), bookmarks: BookmarksManager(pubkey: ""), postbox: PostBox(pool: RelayPool()), bootstrap_relays: [], replies: ReplyCounter(our_pubkey: ""), muted_threads: MutedThreadsManager(keypair: Keypair(pubkey: "", privkey: nil)), wallet: WalletModel(settings: UserSettingsStore())) } return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts(), events: EventCache(), bookmarks: BookmarksManager(pubkey: ""), postbox: PostBox(pool: RelayPool()), bootstrap_relays: [], replies: ReplyCounter(our_pubkey: ""), muted_threads: MutedThreadsManager(keypair: Keypair(pubkey: "", privkey: nil)), wallet: WalletModel(settings: UserSettingsStore()), nav: NavigationCoordinator()) }
} }

View File

@@ -10,7 +10,7 @@ import SwiftUI
enum Route: Hashable { enum Route: Hashable {
case ProfileByKey(pubkey: String) case ProfileByKey(pubkey: String)
case Profile(profile: ProfileModel, followers: FollowersModel) case Profile(profile: ProfileModel, followers: FollowersModel)
case Followers(environmentObject: FollowersModel) case Followers(followers: FollowersModel)
case Relay(relay: String, showActionButtons: Binding<Bool>) case Relay(relay: String, showActionButtons: Binding<Bool>)
case RelayDetail(relay: String, metadata: RelayMetadata) case RelayDetail(relay: String, metadata: RelayMetadata)
case Following(following: FollowingModel) case Following(following: FollowingModel)
@@ -38,34 +38,29 @@ enum Route: Hashable {
case SaveKeys(account: CreateAccountModel) case SaveKeys(account: CreateAccountModel)
case Wallet(wallet: WalletModel) case Wallet(wallet: WalletModel)
case WalletScanner(result: Binding<WalletScanResult>) case WalletScanner(result: Binding<WalletScanResult>)
case FollowersYouKnow(friendedFollowers: [String]) case FollowersYouKnow(friendedFollowers: [String], followers: FollowersModel)
@ViewBuilder @ViewBuilder
func view(navigationCordinator: NavigationCoordinator, damusState: DamusState) -> some View { func view(navigationCordinator: NavigationCoordinator, damusState: DamusState) -> some View {
switch self { switch self {
case .ProfileByKey(let pubkey): case .ProfileByKey(let pubkey):
ProfileView(damus_state: damusState, pubkey: pubkey) ProfileView(damus_state: damusState, pubkey: pubkey)
.environmentObject(navigationCordinator)
case .Profile(let profile, let followers): case .Profile(let profile, let followers):
ProfileView(damus_state: damusState, profile: profile, followers: followers) ProfileView(damus_state: damusState, profile: profile, followers: followers)
.environmentObject(navigationCordinator) case .Followers(let followers):
case .Followers(let environmentObject): FollowersView(damus_state: damusState, followers: followers)
FollowersView(damus_state: damusState)
.environmentObject(environmentObject)
case .Relay(let relay, let showActionButtons): case .Relay(let relay, let showActionButtons):
RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons) RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons)
case .RelayDetail(let relay, let metadata): case .RelayDetail(let relay, let metadata):
RelayDetailView(state: damusState, relay: relay, nip11: metadata) RelayDetailView(state: damusState, relay: relay, nip11: metadata)
case .Following(let following): case .Following(let following):
FollowingView(damus_state: damusState, following: following) FollowingView(damus_state: damusState, following: following)
.environmentObject(navigationCordinator)
case .MuteList(let users): case .MuteList(let users):
MutelistView(damus_state: damusState, users: users) MutelistView(damus_state: damusState, users: users)
case .RelayConfig: case .RelayConfig:
RelayConfigView(state: damusState) RelayConfigView(state: damusState)
case .Bookmarks: case .Bookmarks:
BookmarksView(state: damusState) BookmarksView(state: damusState)
.environmentObject(navigationCordinator)
case .Config: case .Config:
ConfigView(state: damusState) ConfigView(state: damusState)
case .EditMetadata: case .EditMetadata:
@@ -90,34 +85,26 @@ enum Route: Hashable {
ThreadView(state: damusState, thread: thread) ThreadView(state: damusState, thread: thread)
case .Reposts(let reposts): case .Reposts(let reposts):
RepostsView(damus_state: damusState, model: reposts) RepostsView(damus_state: damusState, model: reposts)
.environmentObject(navigationCordinator)
case .Reactions(let reactions): case .Reactions(let reactions):
ReactionsView(damus_state: damusState, model: reactions) ReactionsView(damus_state: damusState, model: reactions)
.environmentObject(navigationCordinator)
case .Zaps(let target): case .Zaps(let target):
ZapsView(state: damusState, target: target) ZapsView(state: damusState, target: target)
case .Search(let search): case .Search(let search):
SearchView(appstate: damusState, search: search) SearchView(appstate: damusState, search: search)
.environmentObject(navigationCordinator)
case .EULA: case .EULA:
EULAView() EULAView(nav: navigationCordinator)
.environmentObject(navigationCordinator)
case .Login: case .Login:
LoginView() LoginView(nav: navigationCordinator)
.environmentObject(navigationCordinator)
case .CreateAccount: case .CreateAccount:
CreateAccountView() CreateAccountView(nav: navigationCordinator)
.environmentObject(navigationCordinator)
case .SaveKeys(let account): case .SaveKeys(let account):
SaveKeysView(account: account) SaveKeysView(account: account)
.environmentObject(navigationCordinator)
case .Wallet(let walletModel): case .Wallet(let walletModel):
WalletView(damus_state: damusState, model: walletModel) WalletView(damus_state: damusState, model: walletModel)
.environmentObject(navigationCordinator)
case .WalletScanner(let walletScanResult): case .WalletScanner(let walletScanResult):
WalletScannerView(result: walletScanResult) WalletScannerView(result: walletScanResult)
case .FollowersYouKnow(let friendedFollowers): case .FollowersYouKnow(let friendedFollowers, let followers):
FollowersYouKnowView(damus_state: damusState, friended_followers: friendedFollowers) FollowersYouKnowView(damus_state: damusState, friended_followers: friendedFollowers, followers: followers)
} }
} }
@@ -183,8 +170,8 @@ enum Route: Hashable {
return true return true
case (.WalletScanner(_), .WalletScanner(_)): case (.WalletScanner(_), .WalletScanner(_)):
return true return true
case (.FollowersYouKnow(let lhs_friendedFollowers), .FollowersYouKnow(let rhs_friendedFollowers)): case (.FollowersYouKnow(_, _), .FollowersYouKnow(_, _)):
return lhs_friendedFollowers == rhs_friendedFollowers return true
default: default:
return false return false
} }
@@ -268,9 +255,10 @@ enum Route: Hashable {
hasher.combine("wallet") hasher.combine("wallet")
case .WalletScanner(_): case .WalletScanner(_):
hasher.combine("walletScanner") hasher.combine("walletScanner")
case .FollowersYouKnow(let friendedFollowers): case .FollowersYouKnow(let friendedFollowers, let followers):
hasher.combine("followersYouKnow") hasher.combine("followersYouKnow")
hasher.combine(friendedFollowers) hasher.combine(friendedFollowers)
hasher.combine(followers.sub_id)
} }
} }
} }

View File

@@ -14,7 +14,6 @@ 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) {
@@ -39,8 +38,6 @@ 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)
} }
} }
} }

View File

@@ -10,7 +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 var nav: NavigationCoordinator
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)
@@ -58,7 +58,7 @@ struct CreateAccountView: View {
.padding(.top, 10) .padding(.top, 10)
Button(action: { Button(action: {
navigationCoordinator.push(route: Route.SaveKeys(account: account)) nav.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.")
@@ -130,7 +130,7 @@ extension View {
struct CreateAccountView_Previews: PreviewProvider { struct CreateAccountView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let model = CreateAccountModel(real: "", nick: "jb55", about: "") let model = CreateAccountModel(real: "", nick: "jb55", about: "")
return CreateAccountView(account: model) return CreateAccountView(account: model, nav: .init())
} }
} }

View File

@@ -19,8 +19,6 @@ 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 {
LazyVStack(spacing: 0) { LazyVStack(spacing: 0) {
@@ -53,7 +51,7 @@ struct DirectMessagesView: View {
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.set_active_dm_model(model) self.model.set_active_dm_model(model)
navigationCoordinator.push(route: Route.DMChat(dms: self.model.active_model)) damus_state.nav.push(route: Route.DMChat(dms: self.model.active_model))
} }
Divider() Divider()

View File

@@ -58,7 +58,7 @@ By using our Application, you signify your acceptance of this EULA. If you do no
struct EULAView: View { struct EULAView: View {
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@EnvironmentObject var navigationCoordinator: NavigationCoordinator var nav: NavigationCoordinator
var body: some View { var body: some View {
ZStack { ZStack {
@@ -91,7 +91,7 @@ struct EULAView: View {
} }
Button(action: { Button(action: {
navigationCoordinator.push(route: Route.Login) nav.push(route: Route.Login)
}) { }) {
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.")
@@ -120,6 +120,6 @@ struct EULAView: View {
struct EULAView_Previews: PreviewProvider { struct EULAView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
EULAView() EULAView(nav: .init())
} }
} }

View File

@@ -10,7 +10,6 @@ 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()
@@ -18,7 +17,7 @@ struct FollowUserView: View {
HStack { HStack {
UserViewRow(damus_state: damus_state, pubkey: target.pubkey) UserViewRow(damus_state: damus_state, pubkey: target.pubkey)
.onTapGesture { .onTapGesture {
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: target.pubkey)) damus_state.nav.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))
@@ -30,8 +29,7 @@ struct FollowUserView: View {
struct FollowersYouKnowView: View { struct FollowersYouKnowView: View {
let damus_state: DamusState let damus_state: DamusState
let friended_followers: [String] let friended_followers: [String]
@ObservedObject var followers: FollowersModel
@EnvironmentObject var followers: FollowersModel
var body: some View { var body: some View {
ScrollView { ScrollView {
@@ -48,16 +46,13 @@ struct FollowersYouKnowView: View {
struct FollowersView: View { struct FollowersView: View {
let damus_state: DamusState let damus_state: DamusState
@ObservedObject 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,14 +72,12 @@ 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()

View File

@@ -37,7 +37,7 @@ struct LoginView: View {
@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 var nav: NavigationCoordinator
func get_error(parsed_key: ParsedKey?) -> String? { func get_error(parsed_key: ParsedKey?) -> String? {
if self.error != nil { if self.error != nil {
@@ -99,8 +99,7 @@ struct LoginView: View {
.padding(.top, 10) .padding(.top, 10)
} }
CreateAccountPrompt() CreateAccountPrompt(nav: nav)
.environmentObject(navigationCoordinator)
.padding(.top, 10) .padding(.top, 10)
Spacer() Spacer()
@@ -330,14 +329,14 @@ struct SignInEntry: View {
} }
struct CreateAccountPrompt: View { struct CreateAccountPrompt: View {
@EnvironmentObject var navigationCoordinator: NavigationCoordinator var nav: 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.")) {
navigationCoordinator.push(route: Route.CreateAccount) nav.push(route: Route.CreateAccount)
} }
Spacer() Spacer()
@@ -351,8 +350,8 @@ struct LoginView_Previews: PreviewProvider {
let pubkey = "npub18m76awca3y37hkvuneavuw6pjj4525fw90necxmadrvjg0sdy6qsngq955" let pubkey = "npub18m76awca3y37hkvuneavuw6pjj4525fw90necxmadrvjg0sdy6qsngq955"
let bech32_pubkey = "KeyInput" let bech32_pubkey = "KeyInput"
Group { Group {
LoginView(key: pubkey) LoginView(key: pubkey, nav: .init())
LoginView(key: bech32_pubkey) LoginView(key: bech32_pubkey, nav: .init())
} }
} }
} }

View File

@@ -193,8 +193,6 @@ 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))")
} }
@@ -239,7 +237,6 @@ 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)

View File

@@ -31,8 +31,6 @@ 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)
} }
@@ -50,19 +48,15 @@ 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(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) { NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) {

View File

@@ -89,7 +89,6 @@ 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) {
@@ -174,7 +173,6 @@ 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

View File

@@ -11,14 +11,12 @@ struct ProfilePicturesView: View {
let state: DamusState let state: DamusState
let pubkeys: [String] let pubkeys: [String]
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
var body: some View { var body: some View {
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 {
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: pubkey)) state.nav.push(route: Route.ProfileByKey(pubkey: pubkey))
} }
} }
} }

View File

@@ -132,8 +132,6 @@ 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)
@@ -415,7 +413,7 @@ struct ProfileView: View {
} }
if followers.contacts != nil { if followers.contacts != nil {
NavigationLink(value: Route.Followers(environmentObject: followers)) { NavigationLink(value: Route.Followers(followers: followers)) {
followersCount followersCount
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
@@ -451,7 +449,7 @@ struct ProfileView: View {
if !friended_followers.isEmpty { if !friended_followers.isEmpty {
Spacer() Spacer()
NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers)) { NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: 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,7 +519,6 @@ 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 {

View File

@@ -45,16 +45,13 @@ 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 profile: Profile? = nil @State var profile: Profile? = nil
@State var error: String? = nil @State var error: String? = nil
@State private var outerTrimEnd: CGFloat = 0 @State private var outerTrimEnd: CGFloat = 0
var animationDuration: Double = 0.5 var animationDuration: Double = 0.5
let generator = UIImpactFeedbackGenerator(style: .light) let generator = UIImpactFeedbackGenerator(style: .light)
@@ -265,7 +262,7 @@ 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) {
if let scanResult { if let scanResult {
navigationCoordinator.push(route: Route.ProfileByKey(pubkey: scanResult.pubkey)) damus_state.nav.push(route: Route.ProfileByKey(pubkey: scanResult.pubkey))
} }
} }
} }

View File

@@ -10,7 +10,6 @@ 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) ?? ""
@@ -23,7 +22,6 @@ 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)
} }
} }
} }

View File

@@ -10,7 +10,6 @@ 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
@@ -19,7 +18,6 @@ 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()

View File

@@ -10,9 +10,6 @@ import SwiftUI
struct RelayFilterView: View { struct RelayFilterView: View {
let state: DamusState let state: DamusState
let timeline: Timeline let timeline: Timeline
//@State var relays: [RelayDescriptor]
//@EnvironmentObject var user_settings: UserSettingsStore
//@State var relays: [RelayDescriptor]
init(state: DamusState, timeline: Timeline) { init(state: DamusState, timeline: Timeline) {
self.state = state self.state = state

View File

@@ -10,11 +10,9 @@ 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)
} }
} }

View File

@@ -10,14 +10,12 @@ 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()

View File

@@ -24,7 +24,6 @@ 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
@@ -108,7 +107,6 @@ struct SearchingEventView: View {
case .found_profile(let pk): case .found_profile(let pk):
NavigationLink(value: Route.ProfileByKey(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:

View File

@@ -14,7 +14,6 @@ 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) })
@@ -68,7 +67,6 @@ 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()
@@ -78,7 +76,6 @@ 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()
@@ -129,9 +126,6 @@ struct SearchHomeView: View {
struct SearchHomeView_Previews: PreviewProvider { struct SearchHomeView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let state = test_damus_state() let state = test_damus_state()
SearchHomeView( SearchHomeView(damus_state: state, model: SearchHomeModel(damus_state: state))
damus_state: state,
model: SearchHomeModel(damus_state: state)
)
} }
} }

View File

@@ -37,11 +37,9 @@ 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 {
@@ -70,7 +68,6 @@ 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)
@@ -109,12 +106,10 @@ 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)

View File

@@ -11,11 +11,9 @@ 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()

View File

@@ -11,11 +11,9 @@ struct SideMenuView: View {
let damus_state: DamusState let damus_state: DamusState
@Binding var isSidebarVisible: Bool @Binding var isSidebarVisible: Bool
@State var confirm_logout: Bool = false @State var confirm_logout: Bool = false
@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
@@ -162,7 +160,6 @@ 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)

View File

@@ -13,8 +13,6 @@ struct InnerTimelineView: View {
let state: DamusState let state: DamusState
let filter: (NostrEvent) -> Bool let filter: (NostrEvent) -> Bool
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
static var count: Int = 0 static var count: Int = 0
init(events: EventHolder, damus: DamusState, filter: @escaping (NostrEvent) -> Bool) { init(events: EventHolder, damus: DamusState, filter: @escaping (NostrEvent) -> Bool) {
@@ -48,7 +46,7 @@ struct InnerTimelineView: View {
.onTapGesture { .onTapGesture {
let event = ev.get_inner_event(cache: state.events) ?? ev let event = ev.get_inner_event(cache: state.events) ?? ev
let thread = ThreadModel(event: event, damus_state: state) let thread = ThreadModel(event: event, damus_state: state)
navigationCoordinator.push(route: Route.Thread(thread: thread)) state.nav.push(route: Route.Thread(thread: thread))
} }
.padding(.top, 7) .padding(.top, 7)
.onAppear { .onAppear {

View File

@@ -8,7 +8,6 @@
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
@@ -28,7 +27,6 @@ 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)

View File

@@ -9,12 +9,12 @@ 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
@State var error: String? = nil @State var error: String? = nil
@State var wallet_scan_result: WalletScanResult = .scanning @State var wallet_scan_result: WalletScanResult = .scanning
var nav: NavigationCoordinator
var body: some View { var body: some View {
MainContent MainContent
@@ -70,7 +70,7 @@ struct ConnectWalletView: View {
} }
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.")) {
navigationCoordinator.push(route: Route.WalletScanner(result: $wallet_scan_result)) nav.push(route: Route.WalletScanner(result: $wallet_scan_result))
} }
if let err = self.error { if let err = self.error {
@@ -96,6 +96,6 @@ struct ConnectWalletView: View {
struct ConnectWalletView_Previews: PreviewProvider { struct ConnectWalletView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ConnectWalletView(model: WalletModel(settings: UserSettingsStore())) ConnectWalletView(model: WalletModel(settings: UserSettingsStore()), nav: .init())
} }
} }

View File

@@ -11,7 +11,6 @@ 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,11 +155,9 @@ struct WalletView: View {
var body: some View { var body: some View {
switch model.connect_state { switch model.connect_state {
case .new: case .new:
ConnectWalletView(model: model) ConnectWalletView(model: model, nav: damus_state.nav)
.environmentObject(navigationCoordinator)
case .none: case .none:
ConnectWalletView(model: model) ConnectWalletView(model: model, nav: damus_state.nav)
.environmentObject(navigationCoordinator)
case .existing(let nwc): case .existing(let nwc):
MainWalletView(nwc: nwc) MainWalletView(nwc: nwc)
.onAppear() { .onAppear() {