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)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ struct ConfigView: View {
|
|||||||
@State var delete_account_warning: Bool = false
|
@State var delete_account_warning: Bool = false
|
||||||
@State var confirm_delete_account: Bool = false
|
@State var confirm_delete_account: Bool = false
|
||||||
@State var delete_text: String = ""
|
@State var delete_text: String = ""
|
||||||
|
|
||||||
@ObservedObject var settings: UserSettingsStore
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
|
||||||
private let DELETE_KEYWORD = "DELETE"
|
private let DELETE_KEYWORD = "DELETE"
|
||||||
|
|
||||||
init(state: DamusState) {
|
init(state: DamusState) {
|
||||||
self.state = state
|
self.state = state
|
||||||
_settings = ObservedObject(initialValue: state.settings)
|
_settings = ObservedObject(initialValue: state.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func textColor() -> Color {
|
func textColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.black : DamusColors.white
|
colorScheme == .light ? DamusColors.black : DamusColors.white
|
||||||
}
|
}
|
||||||
@@ -36,31 +36,30 @@ 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: {
|
||||||
@@ -116,11 +115,11 @@ struct ConfigView: View {
|
|||||||
guard let full_kp = state.keypair.to_full() else {
|
guard let full_kp = state.keypair.to_full() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard delete_text == DELETE_KEYWORD else {
|
guard delete_text == DELETE_KEYWORD else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let ev = created_deleted_account_profile(keypair: full_kp)
|
let ev = created_deleted_account_profile(keypair: full_kp)
|
||||||
state.postbox.send(ev)
|
state.postbox.send(ev)
|
||||||
notify(.logout, ())
|
notify(.logout, ())
|
||||||
@@ -164,7 +163,7 @@ func handle_string_amount(new_value: String) -> Int? {
|
|||||||
guard let amt = NumberFormatter().number(from: filtered) as? Int else {
|
guard let amt = NumberFormatter().number(from: filtered) as? Int else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return amt
|
return amt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ struct DirectMessagesView: View {
|
|||||||
@State var dm_type: DMType = .friend
|
@State var dm_type: DMType = .friend
|
||||||
@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)
|
||||||
@@ -76,12 +76,15 @@ struct FollowingView: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,8 @@ struct EventGroupView: View {
|
|||||||
let state: DamusState
|
let state: DamusState
|
||||||
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])
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ func notification_item_event(events: EventCache, notif: NotificationItem) -> Sho
|
|||||||
struct NotificationItemView: View {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ func followedByString(_ friend_intersection: [String], profiles: Profiles, local
|
|||||||
|
|
||||||
struct EditButton: View {
|
struct EditButton: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
@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)
|
||||||
@@ -92,11 +92,11 @@ struct EditButton: View {
|
|||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillColor() -> Color {
|
func fillColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.black : DamusColors.white
|
colorScheme == .light ? DamusColors.black : DamusColors.white
|
||||||
}
|
}
|
||||||
|
|
||||||
func borderColor() -> Color {
|
func borderColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.black : DamusColors.white
|
colorScheme == .light ? DamusColors.black : DamusColors.white
|
||||||
}
|
}
|
||||||
@@ -104,11 +104,11 @@ struct EditButton: View {
|
|||||||
|
|
||||||
struct VisualEffectView: UIViewRepresentable {
|
struct VisualEffectView: UIViewRepresentable {
|
||||||
var effect: UIVisualEffect?
|
var effect: UIVisualEffect?
|
||||||
|
|
||||||
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView {
|
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView {
|
||||||
UIVisualEffectView()
|
UIVisualEffectView()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) {
|
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) {
|
||||||
uiView.effect = effect
|
uiView.effect = effect
|
||||||
}
|
}
|
||||||
@@ -120,52 +120,54 @@ struct ProfileView: View {
|
|||||||
let bannerHeight: CGFloat = 150.0
|
let bannerHeight: CGFloat = 150.0
|
||||||
|
|
||||||
static let markdown = Markdown()
|
static let markdown = Markdown()
|
||||||
|
|
||||||
@State var is_zoomed: Bool = false
|
@State var is_zoomed: Bool = false
|
||||||
@State var show_share_sheet: Bool = false
|
@State var show_share_sheet: Bool = false
|
||||||
@State var show_qr_code: Bool = false
|
@State var show_qr_code: Bool = false
|
||||||
@State var action_sheet_presented: Bool = false
|
@State var action_sheet_presented: Bool = false
|
||||||
@State var filter_state : FilterState = .posts
|
@State var filter_state : FilterState = .posts
|
||||||
@State var yOffset: CGFloat = 0
|
@State var yOffset: CGFloat = 0
|
||||||
|
|
||||||
@StateObject var profile: ProfileModel
|
@StateObject var profile: ProfileModel
|
||||||
@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)
|
||||||
self._followers = StateObject(wrappedValue: followers)
|
self._followers = StateObject(wrappedValue: followers)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(damus_state: DamusState, pubkey: String) {
|
init(damus_state: DamusState, pubkey: String) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state))
|
self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state))
|
||||||
self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey))
|
self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
@Environment(\.presentationMode) var presentationMode
|
@Environment(\.presentationMode) var presentationMode
|
||||||
|
|
||||||
func imageBorderColor() -> Color {
|
func imageBorderColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.white : DamusColors.black
|
colorScheme == .light ? DamusColors.white : DamusColors.black
|
||||||
}
|
}
|
||||||
|
|
||||||
func bannerBlurViewOpacity() -> Double {
|
func bannerBlurViewOpacity() -> Double {
|
||||||
let progress = -(yOffset + navbarHeight) / 100
|
let progress = -(yOffset + navbarHeight) / 100
|
||||||
return Double(-yOffset > navbarHeight ? progress : 0)
|
return Double(-yOffset > navbarHeight ? progress : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bannerSection: some View {
|
var bannerSection: some View {
|
||||||
GeometryReader { proxy -> AnyView in
|
GeometryReader { proxy -> AnyView in
|
||||||
|
|
||||||
let minY = proxy.frame(in: .global).minY
|
let minY = proxy.frame(in: .global).minY
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.yOffset = minY
|
self.yOffset = minY
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnyView(
|
return AnyView(
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
ZStack {
|
ZStack {
|
||||||
@@ -173,10 +175,10 @@ struct ProfileView: View {
|
|||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.frame(width: proxy.size.width, height: minY > 0 ? bannerHeight + minY : bannerHeight)
|
.frame(width: proxy.size.width, height: minY > 0 ? bannerHeight + minY : bannerHeight)
|
||||||
.clipped()
|
.clipped()
|
||||||
|
|
||||||
VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)).opacity(bannerBlurViewOpacity())
|
VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)).opacity(bannerBlurViewOpacity())
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider().opacity(bannerBlurViewOpacity())
|
Divider().opacity(bannerBlurViewOpacity())
|
||||||
}
|
}
|
||||||
.frame(height: minY > 0 ? bannerHeight + minY : nil)
|
.frame(height: minY > 0 ? bannerHeight + minY : nil)
|
||||||
@@ -187,11 +189,11 @@ struct ProfileView: View {
|
|||||||
.frame(height: bannerHeight)
|
.frame(height: bannerHeight)
|
||||||
.allowsHitTesting(false)
|
.allowsHitTesting(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var navbarHeight: CGFloat {
|
var navbarHeight: CGFloat {
|
||||||
return 100.0 - (Theme.safeAreaInsets?.top ?? 0)
|
return 100.0 - (Theme.safeAreaInsets?.top ?? 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func navImage(img: String) -> some View {
|
func navImage(img: String) -> some View {
|
||||||
Image(img)
|
Image(img)
|
||||||
@@ -199,7 +201,7 @@ struct ProfileView: View {
|
|||||||
.background(Color.black.opacity(0.6))
|
.background(Color.black.opacity(0.6))
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
}
|
}
|
||||||
|
|
||||||
var navBackButton: some View {
|
var navBackButton: some View {
|
||||||
Button {
|
Button {
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
@@ -207,7 +209,7 @@ struct ProfileView: View {
|
|||||||
navImage(img: "chevron-left")
|
navImage(img: "chevron-left")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var navActionSheetButton: some View {
|
var navActionSheetButton: some View {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
action_sheet_presented = true
|
action_sheet_presented = true
|
||||||
@@ -218,7 +220,7 @@ struct ProfileView: View {
|
|||||||
Button(NSLocalizedString("Share", comment: "Button to share the link to a profile.")) {
|
Button(NSLocalizedString("Share", comment: "Button to share the link to a profile.")) {
|
||||||
show_share_sheet = true
|
show_share_sheet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(NSLocalizedString("QR Code", comment: "Button to view profile's qr code.")) {
|
Button(NSLocalizedString("QR Code", comment: "Button to view profile's qr code.")) {
|
||||||
show_qr_code = true
|
show_qr_code = true
|
||||||
}
|
}
|
||||||
@@ -238,7 +240,7 @@ struct ProfileView: View {
|
|||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: profile.pubkey) else {
|
guard let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: profile.pubkey) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -254,7 +256,7 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var customNavbar: some View {
|
var customNavbar: some View {
|
||||||
HStack {
|
HStack {
|
||||||
navBackButton
|
navBackButton
|
||||||
@@ -265,7 +267,7 @@ struct ProfileView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.accentColor(DamusColors.white)
|
.accentColor(DamusColors.white)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lnButton(lnurl: String, profile: Profile) -> some View {
|
func lnButton(lnurl: String, profile: Profile) -> some View {
|
||||||
let button_img = profile.reactions == false ? "zap.fill" : "zap"
|
let button_img = profile.reactions == false ? "zap.fill" : "zap"
|
||||||
return Button(action: {
|
return Button(action: {
|
||||||
@@ -278,7 +280,7 @@ struct ProfileView: View {
|
|||||||
if profile.reactions == false {
|
if profile.reactions == false {
|
||||||
Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.")
|
Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if let addr = profile.lud16 {
|
if let addr = profile.lud16 {
|
||||||
Button {
|
Button {
|
||||||
UIPasteboard.general.string = addr
|
UIPasteboard.general.string = addr
|
||||||
@@ -293,31 +295,30 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.cornerRadius(24)
|
.cornerRadius(24)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func actionSection(profile_data: Profile?) -> some View {
|
func actionSection(profile_data: Profile?) -> some View {
|
||||||
return Group {
|
return Group {
|
||||||
|
|
||||||
if let profile = profile_data {
|
if let profile = profile_data {
|
||||||
if let lnurl = profile.lnurl, lnurl != "" {
|
if let lnurl = profile.lnurl, lnurl != "" {
|
||||||
lnButton(lnurl: lnurl, profile: profile)
|
lnButton(lnurl: lnurl, profile: profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dmButton
|
dmButton
|
||||||
|
|
||||||
if profile.pubkey != damus_state.pubkey {
|
if profile.pubkey != damus_state.pubkey {
|
||||||
FollowButtonView(
|
FollowButtonView(
|
||||||
target: profile.get_follow_target(),
|
target: profile.get_follow_target(),
|
||||||
@@ -325,26 +326,26 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfpOffset() -> CGFloat {
|
func pfpOffset() -> CGFloat {
|
||||||
let progress = -yOffset / navbarHeight
|
let progress = -yOffset / navbarHeight
|
||||||
let offset = (pfp_size / 4.0) * (progress < 1.0 ? progress : 1)
|
let offset = (pfp_size / 4.0) * (progress < 1.0 ? progress : 1)
|
||||||
return offset > 0 ? offset : 0
|
return offset > 0 ? offset : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfpScale() -> CGFloat {
|
func pfpScale() -> CGFloat {
|
||||||
let progress = -yOffset / navbarHeight
|
let progress = -yOffset / navbarHeight
|
||||||
let scale = 1.0 - (0.5 * (progress < 1.0 ? progress : 1))
|
let scale = 1.0 - (0.5 * (progress < 1.0 ? progress : 1))
|
||||||
return scale < 1 ? scale : 1
|
return scale < 1 ? scale : 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func nameSection(profile_data: Profile?) -> some View {
|
func nameSection(profile_data: Profile?) -> some View {
|
||||||
return Group {
|
return Group {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
@@ -358,17 +359,17 @@ struct ProfileView: View {
|
|||||||
.fullScreenCover(isPresented: $is_zoomed) {
|
.fullScreenCover(isPresented: $is_zoomed) {
|
||||||
ProfilePicImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
ProfilePicImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
actionSection(profile_data: profile_data)
|
actionSection(profile_data: profile_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
|
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
|
||||||
ProfileNameView(pubkey: profile.pubkey, profile: profile_data, follows_you: follows_you, damus: damus_state)
|
ProfileNameView(pubkey: profile.pubkey, profile: profile_data, follows_you: follows_you, damus: damus_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var followersCount: some View {
|
var followersCount: some View {
|
||||||
HStack {
|
HStack {
|
||||||
if followers.count == nil {
|
if followers.count == nil {
|
||||||
@@ -385,26 +386,26 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var aboutSection: some View {
|
var aboutSection: some View {
|
||||||
VStack(alignment: .leading, spacing: 8.0) {
|
VStack(alignment: .leading, spacing: 8.0) {
|
||||||
let profile_data = damus_state.profiles.lookup(id: profile.pubkey)
|
let profile_data = damus_state.profiles.lookup(id: profile.pubkey)
|
||||||
|
|
||||||
nameSection(profile_data: profile_data)
|
nameSection(profile_data: profile_data)
|
||||||
|
|
||||||
if let about = profile_data?.about {
|
if let about = profile_data?.about {
|
||||||
AboutView(state: damus_state, about: about)
|
AboutView(state: damus_state, about: about)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let url = profile_data?.website_url {
|
if let url = profile_data?.website_url {
|
||||||
WebsiteLink(url: url)
|
WebsiteLink(url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
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())
|
||||||
@@ -427,18 +427,18 @@ struct ProfileView: View {
|
|||||||
followers.subscribe()
|
followers.subscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let relays = profile.relays {
|
if let relays = profile.relays {
|
||||||
// Only open relay config view if the user is logged in with private key and they are looking at their own profile.
|
// Only open relay config view if the user is logged in with private key and they are looking at their own profile.
|
||||||
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))
|
||||||
@@ -464,7 +464,7 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
ScrollView(.vertical) {
|
ScrollView(.vertical) {
|
||||||
@@ -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 {
|
||||||
@@ -542,7 +543,7 @@ struct ProfileView_Previews: PreviewProvider {
|
|||||||
func test_damus_state() -> DamusState {
|
func test_damus_state() -> DamusState {
|
||||||
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||||
let damus = DamusState.empty
|
let damus = DamusState.empty
|
||||||
|
|
||||||
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", banner: "", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io", damus_donation: nil)
|
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", banner: "", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io", damus_donation: nil)
|
||||||
let tsprof = TimestampedProfile(profile: prof, timestamp: 0, event: test_event)
|
let tsprof = TimestampedProfile(profile: prof, timestamp: 0, event: test_event)
|
||||||
damus.profiles.add(id: pubkey, profile: tsprof)
|
damus.profiles.add(id: pubkey, profile: tsprof)
|
||||||
@@ -551,15 +552,15 @@ func test_damus_state() -> DamusState {
|
|||||||
|
|
||||||
struct KeyView: View {
|
struct KeyView: View {
|
||||||
let pubkey: String
|
let pubkey: String
|
||||||
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
@State private var isCopied = false
|
@State private var isCopied = false
|
||||||
|
|
||||||
func keyColor() -> Color {
|
func keyColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.black : DamusColors.white
|
colorScheme == .light ? DamusColors.black : DamusColors.white
|
||||||
}
|
}
|
||||||
|
|
||||||
private func copyPubkey(_ pubkey: String) {
|
private func copyPubkey(_ pubkey: String) {
|
||||||
UIPasteboard.general.string = pubkey
|
UIPasteboard.general.string = pubkey
|
||||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||||
@@ -572,10 +573,10 @@ struct KeyView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let bech32 = bech32_pubkey(pubkey) ?? pubkey
|
let bech32 = bech32_pubkey(pubkey) ?? pubkey
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text(verbatim: "\(abbrev_pubkey(bech32, amount: 16))")
|
Text(verbatim: "\(abbrev_pubkey(bech32, amount: 16))")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
@@ -583,7 +584,7 @@ struct KeyView: View {
|
|||||||
.padding(5)
|
.padding(5)
|
||||||
.padding([.leading, .trailing], 5)
|
.padding([.leading, .trailing], 5)
|
||||||
.background(RoundedRectangle(cornerRadius: 11).foregroundColor(DamusColors.adaptableGrey))
|
.background(RoundedRectangle(cornerRadius: 11).foregroundColor(DamusColors.adaptableGrey))
|
||||||
|
|
||||||
if isCopied != true {
|
if isCopied != true {
|
||||||
Button {
|
Button {
|
||||||
copyPubkey(bech32)
|
copyPubkey(bech32)
|
||||||
|
|||||||
@@ -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.")) {
|
||||||
UserViewRow(damus_state: state, pubkey: pubkey)
|
NavigationLink(value: Route.ProfileByKey(pubkey: pubkey), label: {
|
||||||
|
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())
|
||||||
|
|||||||
@@ -11,23 +11,24 @@ 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
|
||||||
let padding: CGFloat = 30
|
let padding: CGFloat = 30
|
||||||
|
|
||||||
func fillColor() -> Color {
|
func fillColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.white : DamusColors.black
|
colorScheme == .light ? DamusColors.white : DamusColors.black
|
||||||
}
|
}
|
||||||
|
|
||||||
func textColor() -> Color {
|
func textColor() -> Color {
|
||||||
colorScheme == .light ? DamusColors.black : DamusColors.white
|
colorScheme == .light ? DamusColors.black : DamusColors.white
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
GeometryReader { _ in
|
GeometryReader { _ in
|
||||||
@@ -42,20 +43,20 @@ struct SideMenuView: View {
|
|||||||
content
|
content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
Image("wallet")
|
Image("wallet")
|
||||||
.tint(DamusColors.adaptableBlack)
|
.tint(DamusColors.adaptableBlack)
|
||||||
|
|
||||||
Text(NSLocalizedString("wallet", comment: "Sidebar menu label for Wallet view."))
|
Text(NSLocalizedString("wallet", comment: "Sidebar menu label for Wallet view."))
|
||||||
.font(.title2)
|
.font(.title2)
|
||||||
.foregroundColor(textColor())
|
.foregroundColor(textColor())
|
||||||
@@ -63,36 +64,35 @@ struct SideMenuView: View {
|
|||||||
.dynamicTypeSize(.xSmall)
|
.dynamicTypeSize(.xSmall)
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var MainSidemenu: some View {
|
var MainSidemenu: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
|
let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||||
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)
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if let display_name = profile?.display_name {
|
if let display_name = profile?.display_name {
|
||||||
Text(display_name)
|
Text(display_name)
|
||||||
@@ -109,10 +109,10 @@ struct SideMenuView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.bottom, verticalSpacing)
|
.padding(.bottom, verticalSpacing)
|
||||||
}
|
})
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SidemenuItems(profile_model: profile_model, followers: followers)
|
SidemenuItems(profile_model: profile_model, followers: followers)
|
||||||
.labelStyle(SideMenuLabelStyle())
|
.labelStyle(SideMenuLabelStyle())
|
||||||
@@ -120,21 +120,21 @@ struct SideMenuView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var content: some View {
|
var content: some View {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
fillColor()
|
fillColor()
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
MainSidemenu
|
MainSidemenu
|
||||||
.simultaneousGesture(TapGesture().onEnded {
|
.simultaneousGesture(TapGesture().onEnded {
|
||||||
isSidebarVisible = false
|
isSidebarVisible = false
|
||||||
})
|
})
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
HStack() {
|
HStack() {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
//ConfigView(state: damus_state)
|
//ConfigView(state: damus_state)
|
||||||
@@ -150,9 +150,9 @@ struct SideMenuView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.dynamicTypeSize(.xSmall)
|
.dynamicTypeSize(.xSmall)
|
||||||
})
|
})
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
showQRCode.toggle()
|
showQRCode.toggle()
|
||||||
}, label: {
|
}, label: {
|
||||||
@@ -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)
|
||||||
@@ -186,20 +187,20 @@ struct SideMenuView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func navLabel(title: String, img: String) -> some View {
|
func navLabel(title: String, img: String) -> some View {
|
||||||
Image(img)
|
Image(img)
|
||||||
.tint(DamusColors.adaptableBlack)
|
.tint(DamusColors.adaptableBlack)
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.title2)
|
.font(.title2)
|
||||||
.foregroundColor(textColor())
|
.foregroundColor(textColor())
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.dynamicTypeSize(.xSmall)
|
.dynamicTypeSize(.xSmall)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SideMenuLabelStyle: LabelStyle {
|
struct SideMenuLabelStyle: LabelStyle {
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
HStack(alignment: .center, spacing: 8) {
|
HStack(alignment: .center, spacing: 8) {
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -63,17 +64,13 @@ 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