mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
Compare commits
14 Commits
122775e586
...
b31b917b70
Author | SHA1 | Date | |
---|---|---|---|
|
b31b917b70 | ||
|
c521998158 | ||
|
3f1f257df2 | ||
|
1339ec3ded | ||
|
770a845b36 | ||
|
68dd47130e | ||
|
8cdbc84093 | ||
|
6111e244de | ||
|
0043f0059d | ||
|
4413ec0ec5 | ||
|
9a83872a22 | ||
|
988da17b06 | ||
|
5e530bfc9c | ||
|
0719e94fbc |
@ -30,6 +30,7 @@ Damus has also graciously received donations or grants from hundreds of Damus us
|
|||||||
damus implements the following [Nostr Implementation Possibilities][nips]
|
damus implements the following [Nostr Implementation Possibilities][nips]
|
||||||
|
|
||||||
- [NIP-01: Basic protocol flow][nip01]
|
- [NIP-01: Basic protocol flow][nip01]
|
||||||
|
- [NIP-04: Encrypted direct message][nip04]
|
||||||
- [NIP-08: Mentions][nip08]
|
- [NIP-08: Mentions][nip08]
|
||||||
- [NIP-10: Reply conventions][nip10]
|
- [NIP-10: Reply conventions][nip10]
|
||||||
- [NIP-12: Generic tag queries (hashtags)][nip12]
|
- [NIP-12: Generic tag queries (hashtags)][nip12]
|
||||||
@ -41,6 +42,7 @@ damus implements the following [Nostr Implementation Possibilities][nips]
|
|||||||
|
|
||||||
[nips]: https://github.com/nostr-protocol/nips
|
[nips]: https://github.com/nostr-protocol/nips
|
||||||
[nip01]: https://github.com/nostr-protocol/nips/blob/master/01.md
|
[nip01]: https://github.com/nostr-protocol/nips/blob/master/01.md
|
||||||
|
[nip04]: https://github.com/nostr-protocol/nips/blob/master/04.md
|
||||||
[nip08]: https://github.com/nostr-protocol/nips/blob/master/08.md
|
[nip08]: https://github.com/nostr-protocol/nips/blob/master/08.md
|
||||||
[nip10]: https://github.com/nostr-protocol/nips/blob/master/10.md
|
[nip10]: https://github.com/nostr-protocol/nips/blob/master/10.md
|
||||||
[nip12]: https://github.com/nostr-protocol/nips/blob/master/12.md
|
[nip12]: https://github.com/nostr-protocol/nips/blob/master/12.md
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; };
|
3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; };
|
||||||
3A90B1812A4EA3AF00000D94 /* UserSearchCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A90B1802A4EA3AF00000D94 /* UserSearchCache.swift */; };
|
3A90B1812A4EA3AF00000D94 /* UserSearchCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A90B1802A4EA3AF00000D94 /* UserSearchCache.swift */; };
|
||||||
3A90B1832A4EA3C600000D94 /* UserSearchCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A90B1822A4EA3C600000D94 /* UserSearchCacheTests.swift */; };
|
3A90B1832A4EA3C600000D94 /* UserSearchCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A90B1822A4EA3C600000D94 /* UserSearchCacheTests.swift */; };
|
||||||
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
|
|
||||||
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
|
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
|
||||||
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
|
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
|
||||||
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA59D1C2999B0400061C48E /* DraftsModel.swift */; };
|
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA59D1C2999B0400061C48E /* DraftsModel.swift */; };
|
||||||
@ -61,7 +60,6 @@
|
|||||||
4C1253662A76D0FF0004F4B8 /* OnlyZapsNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253652A76D0FF0004F4B8 /* OnlyZapsNotify.swift */; };
|
4C1253662A76D0FF0004F4B8 /* OnlyZapsNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253652A76D0FF0004F4B8 /* OnlyZapsNotify.swift */; };
|
||||||
4C1253682A76D2470004F4B8 /* MuteNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253672A76D2470004F4B8 /* MuteNotify.swift */; };
|
4C1253682A76D2470004F4B8 /* MuteNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253672A76D2470004F4B8 /* MuteNotify.swift */; };
|
||||||
4C12536A2A76D3850004F4B8 /* RelaysChangedNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */; };
|
4C12536A2A76D3850004F4B8 /* RelaysChangedNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */; };
|
||||||
4C12536C2A76D4B00004F4B8 /* RepostedNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C12536B2A76D4B00004F4B8 /* RepostedNotify.swift */; };
|
|
||||||
4C15C7152A55DE7A00D0A0DB /* ReactionsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C15C7142A55DE7A00D0A0DB /* ReactionsSettingsView.swift */; };
|
4C15C7152A55DE7A00D0A0DB /* ReactionsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C15C7142A55DE7A00D0A0DB /* ReactionsSettingsView.swift */; };
|
||||||
4C190F202A535FC200027FD5 /* CustomizeZapModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C190F1F2A535FC200027FD5 /* CustomizeZapModel.swift */; };
|
4C190F202A535FC200027FD5 /* CustomizeZapModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C190F1F2A535FC200027FD5 /* CustomizeZapModel.swift */; };
|
||||||
4C190F252A547D2000027FD5 /* LoadScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C190F242A547D2000027FD5 /* LoadScript.swift */; };
|
4C190F252A547D2000027FD5 /* LoadScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C190F242A547D2000027FD5 /* LoadScript.swift */; };
|
||||||
@ -255,6 +253,7 @@
|
|||||||
4C9146FD2A2A87C200DDEA40 /* wasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9276E2A2A5D110098A105 /* wasm.c */; };
|
4C9146FD2A2A87C200DDEA40 /* wasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9276E2A2A5D110098A105 /* wasm.c */; };
|
||||||
4C9146FE2A2A87C200DDEA40 /* nostrscript.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C4F14A92A2A71AB0045A0B9 /* nostrscript.c */; };
|
4C9146FE2A2A87C200DDEA40 /* nostrscript.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C4F14A92A2A71AB0045A0B9 /* nostrscript.c */; };
|
||||||
4C9147002A2A891E00DDEA40 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C9146FF2A2A891E00DDEA40 /* error.c */; };
|
4C9147002A2A891E00DDEA40 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C9146FF2A2A891E00DDEA40 /* error.c */; };
|
||||||
|
4C94D6432BA5AEFE00C26EFF /* QuoteRepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C94D6422BA5AEFE00C26EFF /* QuoteRepostsView.swift */; };
|
||||||
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; };
|
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; };
|
||||||
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */; };
|
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */; };
|
||||||
4C9B0DEE2A65A75F00CBDA21 /* AttrStringTestExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9B0DED2A65A75F00CBDA21 /* AttrStringTestExtensions.swift */; };
|
4C9B0DEE2A65A75F00CBDA21 /* AttrStringTestExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9B0DED2A65A75F00CBDA21 /* AttrStringTestExtensions.swift */; };
|
||||||
@ -288,14 +287,12 @@
|
|||||||
4CAAD8B029888AD200060CEA /* RelayConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */; };
|
4CAAD8B029888AD200060CEA /* RelayConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */; };
|
||||||
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; };
|
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; };
|
||||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9DB280C38C000D9BBE8 /* Profiles.swift */; };
|
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9DB280C38C000D9BBE8 /* Profiles.swift */; };
|
||||||
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */; };
|
|
||||||
4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF4295E679D007FD187 /* UserRelaysView.swift */; };
|
4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF4295E679D007FD187 /* UserRelaysView.swift */; };
|
||||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838529656C8B00DC99E7 /* NIP05.swift */; };
|
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838529656C8B00DC99E7 /* NIP05.swift */; };
|
||||||
4CB88389296AF99A00DC99E7 /* EventDetailBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */; };
|
4CB88389296AF99A00DC99E7 /* EventDetailBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */; };
|
||||||
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */; };
|
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */; };
|
||||||
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838C296F710400DC99E7 /* Reposted.swift */; };
|
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838C296F710400DC99E7 /* Reposted.swift */; };
|
||||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838E296F781C00DC99E7 /* ReactionsView.swift */; };
|
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838E296F781C00DC99E7 /* ReactionsView.swift */; };
|
||||||
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88392296F798300DC99E7 /* ReactionsModel.swift */; };
|
|
||||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88395296F7F8B00DC99E7 /* ReactionView.swift */; };
|
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88395296F7F8B00DC99E7 /* ReactionView.swift */; };
|
||||||
4CB8839A297322D200DC99E7 /* DMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88399297322D200DC99E7 /* DMTests.swift */; };
|
4CB8839A297322D200DC99E7 /* DMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88399297322D200DC99E7 /* DMTests.swift */; };
|
||||||
4CB883A62975F83C00DC99E7 /* LNUrlPayRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB883A52975F83C00DC99E7 /* LNUrlPayRequest.swift */; };
|
4CB883A62975F83C00DC99E7 /* LNUrlPayRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB883A52975F83C00DC99E7 /* LNUrlPayRequest.swift */; };
|
||||||
@ -404,6 +401,8 @@
|
|||||||
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E1DAC2A193EC2008FC15A /* GradientButtonStyle.swift */; };
|
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E1DAC2A193EC2008FC15A /* GradientButtonStyle.swift */; };
|
||||||
5C6E1DAF2A194075008FC15A /* PinkGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E1DAE2A194075008FC15A /* PinkGradient.swift */; };
|
5C6E1DAF2A194075008FC15A /* PinkGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E1DAE2A194075008FC15A /* PinkGradient.swift */; };
|
||||||
5C7389B12B6EFA7100781E0A /* ProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7389B02B6EFA7100781E0A /* ProxyView.swift */; };
|
5C7389B12B6EFA7100781E0A /* ProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7389B02B6EFA7100781E0A /* ProxyView.swift */; };
|
||||||
|
5C7389B72B9E692E00781E0A /* MutinyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7389B62B9E692E00781E0A /* MutinyButton.swift */; };
|
||||||
|
5C7389B92B9E69ED00781E0A /* MutinyGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7389B82B9E69ED00781E0A /* MutinyGradient.swift */; };
|
||||||
5CC868DD2AA29B3200FB22BA /* NeutralButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868DC2AA29B3200FB22BA /* NeutralButtonStyle.swift */; };
|
5CC868DD2AA29B3200FB22BA /* NeutralButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868DC2AA29B3200FB22BA /* NeutralButtonStyle.swift */; };
|
||||||
5CF2DCCC2AA3AF0B00984B8D /* RelayPicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF2DCCB2AA3AF0B00984B8D /* RelayPicView.swift */; };
|
5CF2DCCC2AA3AF0B00984B8D /* RelayPicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF2DCCB2AA3AF0B00984B8D /* RelayPicView.swift */; };
|
||||||
5CF2DCCE2AABE1A500984B8D /* DamusLightGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */; };
|
5CF2DCCE2AABE1A500984B8D /* DamusLightGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */; };
|
||||||
@ -769,7 +768,6 @@
|
|||||||
3A96D41A298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
3A96D41A298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
3A96D41B298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
3A96D41B298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
3A96D41C298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
3A96D41C298DA94500388A2A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepostsModel.swift; sourceTree = "<group>"; };
|
|
||||||
3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; };
|
3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; };
|
||||||
3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; };
|
3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; };
|
||||||
3AA59D1C2999B0400061C48E /* DraftsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsModel.swift; sourceTree = "<group>"; };
|
3AA59D1C2999B0400061C48E /* DraftsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsModel.swift; sourceTree = "<group>"; };
|
||||||
@ -843,7 +841,6 @@
|
|||||||
4C1253652A76D0FF0004F4B8 /* OnlyZapsNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlyZapsNotify.swift; sourceTree = "<group>"; };
|
4C1253652A76D0FF0004F4B8 /* OnlyZapsNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlyZapsNotify.swift; sourceTree = "<group>"; };
|
||||||
4C1253672A76D2470004F4B8 /* MuteNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteNotify.swift; sourceTree = "<group>"; };
|
4C1253672A76D2470004F4B8 /* MuteNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteNotify.swift; sourceTree = "<group>"; };
|
||||||
4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaysChangedNotify.swift; sourceTree = "<group>"; };
|
4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaysChangedNotify.swift; sourceTree = "<group>"; };
|
||||||
4C12536B2A76D4B00004F4B8 /* RepostedNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostedNotify.swift; sourceTree = "<group>"; };
|
|
||||||
4C15C7142A55DE7A00D0A0DB /* ReactionsSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsSettingsView.swift; sourceTree = "<group>"; };
|
4C15C7142A55DE7A00D0A0DB /* ReactionsSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsSettingsView.swift; sourceTree = "<group>"; };
|
||||||
4C190F1F2A535FC200027FD5 /* CustomizeZapModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeZapModel.swift; sourceTree = "<group>"; };
|
4C190F1F2A535FC200027FD5 /* CustomizeZapModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeZapModel.swift; sourceTree = "<group>"; };
|
||||||
4C190F242A547D2000027FD5 /* LoadScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadScript.swift; sourceTree = "<group>"; };
|
4C190F242A547D2000027FD5 /* LoadScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadScript.swift; sourceTree = "<group>"; };
|
||||||
@ -1165,6 +1162,7 @@
|
|||||||
4C90BD19283AA67F008EE7EF /* Bech32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32.swift; sourceTree = "<group>"; };
|
4C90BD19283AA67F008EE7EF /* Bech32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32.swift; sourceTree = "<group>"; };
|
||||||
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
|
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
|
||||||
4C9146FF2A2A891E00DDEA40 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
|
4C9146FF2A2A891E00DDEA40 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
|
||||||
|
4C94D6422BA5AEFE00C26EFF /* QuoteRepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteRepostsView.swift; sourceTree = "<group>"; };
|
||||||
4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; };
|
4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; };
|
||||||
4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationStatusModel.swift; sourceTree = "<group>"; };
|
4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationStatusModel.swift; sourceTree = "<group>"; };
|
||||||
4C9B0DED2A65A75F00CBDA21 /* AttrStringTestExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttrStringTestExtensions.swift; sourceTree = "<group>"; };
|
4C9B0DED2A65A75F00CBDA21 /* AttrStringTestExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttrStringTestExtensions.swift; sourceTree = "<group>"; };
|
||||||
@ -1205,14 +1203,12 @@
|
|||||||
4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConfigView.swift; sourceTree = "<group>"; };
|
4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConfigView.swift; sourceTree = "<group>"; };
|
||||||
4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyView.swift; sourceTree = "<group>"; };
|
4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyView.swift; sourceTree = "<group>"; };
|
||||||
4CACA9DB280C38C000D9BBE8 /* Profiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profiles.swift; sourceTree = "<group>"; };
|
4CACA9DB280C38C000D9BBE8 /* Profiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profiles.swift; sourceTree = "<group>"; };
|
||||||
4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendedRelayView.swift; sourceTree = "<group>"; };
|
|
||||||
4CB55EF4295E679D007FD187 /* UserRelaysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRelaysView.swift; sourceTree = "<group>"; };
|
4CB55EF4295E679D007FD187 /* UserRelaysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRelaysView.swift; sourceTree = "<group>"; };
|
||||||
4CB8838529656C8B00DC99E7 /* NIP05.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05.swift; sourceTree = "<group>"; };
|
4CB8838529656C8B00DC99E7 /* NIP05.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05.swift; sourceTree = "<group>"; };
|
||||||
4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailBar.swift; sourceTree = "<group>"; };
|
4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailBar.swift; sourceTree = "<group>"; };
|
||||||
4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05Badge.swift; sourceTree = "<group>"; };
|
4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05Badge.swift; sourceTree = "<group>"; };
|
||||||
4CB8838C296F710400DC99E7 /* Reposted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reposted.swift; sourceTree = "<group>"; };
|
4CB8838C296F710400DC99E7 /* Reposted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reposted.swift; sourceTree = "<group>"; };
|
||||||
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsView.swift; sourceTree = "<group>"; };
|
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsView.swift; sourceTree = "<group>"; };
|
||||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsModel.swift; sourceTree = "<group>"; };
|
|
||||||
4CB88395296F7F8B00DC99E7 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = "<group>"; };
|
4CB88395296F7F8B00DC99E7 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = "<group>"; };
|
||||||
4CB88399297322D200DC99E7 /* DMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMTests.swift; sourceTree = "<group>"; };
|
4CB88399297322D200DC99E7 /* DMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMTests.swift; sourceTree = "<group>"; };
|
||||||
4CB883A52975F83C00DC99E7 /* LNUrlPayRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNUrlPayRequest.swift; sourceTree = "<group>"; };
|
4CB883A52975F83C00DC99E7 /* LNUrlPayRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNUrlPayRequest.swift; sourceTree = "<group>"; };
|
||||||
@ -1326,6 +1322,8 @@
|
|||||||
5C6E1DAC2A193EC2008FC15A /* GradientButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientButtonStyle.swift; sourceTree = "<group>"; };
|
5C6E1DAC2A193EC2008FC15A /* GradientButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientButtonStyle.swift; sourceTree = "<group>"; };
|
||||||
5C6E1DAE2A194075008FC15A /* PinkGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinkGradient.swift; sourceTree = "<group>"; };
|
5C6E1DAE2A194075008FC15A /* PinkGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinkGradient.swift; sourceTree = "<group>"; };
|
||||||
5C7389B02B6EFA7100781E0A /* ProxyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyView.swift; sourceTree = "<group>"; };
|
5C7389B02B6EFA7100781E0A /* ProxyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyView.swift; sourceTree = "<group>"; };
|
||||||
|
5C7389B62B9E692E00781E0A /* MutinyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutinyButton.swift; sourceTree = "<group>"; };
|
||||||
|
5C7389B82B9E69ED00781E0A /* MutinyGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutinyGradient.swift; sourceTree = "<group>"; };
|
||||||
5CC868DC2AA29B3200FB22BA /* NeutralButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeutralButtonStyle.swift; sourceTree = "<group>"; };
|
5CC868DC2AA29B3200FB22BA /* NeutralButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeutralButtonStyle.swift; sourceTree = "<group>"; };
|
||||||
5CF2DCCB2AA3AF0B00984B8D /* RelayPicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayPicView.swift; sourceTree = "<group>"; };
|
5CF2DCCB2AA3AF0B00984B8D /* RelayPicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayPicView.swift; sourceTree = "<group>"; };
|
||||||
5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLightGradient.swift; sourceTree = "<group>"; };
|
5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLightGradient.swift; sourceTree = "<group>"; };
|
||||||
@ -1510,6 +1508,7 @@
|
|||||||
children = (
|
children = (
|
||||||
3AA24801297E3DC20090C62D /* RepostView.swift */,
|
3AA24801297E3DC20090C62D /* RepostView.swift */,
|
||||||
4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */,
|
4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */,
|
||||||
|
4C94D6422BA5AEFE00C26EFF /* QuoteRepostsView.swift */,
|
||||||
);
|
);
|
||||||
path = Reposts;
|
path = Reposts;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1588,7 +1587,6 @@
|
|||||||
BA3759882ABCCDE30018D73B /* Camera */,
|
BA3759882ABCCDE30018D73B /* Camera */,
|
||||||
4C190F1E2A535FC200027FD5 /* Zaps */,
|
4C190F1E2A535FC200027FD5 /* Zaps */,
|
||||||
4C54AA0829A55416003E4487 /* Notifications */,
|
4C54AA0829A55416003E4487 /* Notifications */,
|
||||||
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */,
|
|
||||||
4C0A3F8E280F640A000448DE /* ThreadModel.swift */,
|
4C0A3F8E280F640A000448DE /* ThreadModel.swift */,
|
||||||
4C0A3F92280F66F5000448DE /* ReplyMap.swift */,
|
4C0A3F92280F66F5000448DE /* ReplyMap.swift */,
|
||||||
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */,
|
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */,
|
||||||
@ -1618,7 +1616,6 @@
|
|||||||
4C216F372871EDE300040376 /* DirectMessageModel.swift */,
|
4C216F372871EDE300040376 /* DirectMessageModel.swift */,
|
||||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */,
|
BA693073295D649800ADDB87 /* UserSettingsStore.swift */,
|
||||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
|
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
|
||||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */,
|
|
||||||
4CF0ABD32980996B00D66079 /* Report.swift */,
|
4CF0ABD32980996B00D66079 /* Report.swift */,
|
||||||
3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */,
|
3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */,
|
||||||
3AAA95C9298DF87B00F3D526 /* TranslationService.swift */,
|
3AAA95C9298DF87B00F3D526 /* TranslationService.swift */,
|
||||||
@ -2112,6 +2109,7 @@
|
|||||||
5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */,
|
5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */,
|
||||||
4C687C202A5F7ED00092C550 /* DamusBackground.swift */,
|
4C687C202A5F7ED00092C550 /* DamusBackground.swift */,
|
||||||
5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */,
|
5CF2DCCD2AABE1A500984B8D /* DamusLightGradient.swift */,
|
||||||
|
5C7389B82B9E69ED00781E0A /* MutinyGradient.swift */,
|
||||||
);
|
);
|
||||||
path = Gradients;
|
path = Gradients;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2182,6 +2180,7 @@
|
|||||||
4C8D1A6E29F31E5000ACDF75 /* FriendsButton.swift */,
|
4C8D1A6E29F31E5000ACDF75 /* FriendsButton.swift */,
|
||||||
F71694F32A6732B7001F4053 /* GradientFollowButton.swift */,
|
F71694F32A6732B7001F4053 /* GradientFollowButton.swift */,
|
||||||
4C7D09652A0AE62100943473 /* AlbyButton.swift */,
|
4C7D09652A0AE62100943473 /* AlbyButton.swift */,
|
||||||
|
5C7389B62B9E692E00781E0A /* MutinyButton.swift */,
|
||||||
);
|
);
|
||||||
path = Buttons;
|
path = Buttons;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2258,7 +2257,6 @@
|
|||||||
4C86F7C32A76C44C00EC0817 /* ZappingNotify.swift */,
|
4C86F7C32A76C44C00EC0817 /* ZappingNotify.swift */,
|
||||||
4C1253672A76D2470004F4B8 /* MuteNotify.swift */,
|
4C1253672A76D2470004F4B8 /* MuteNotify.swift */,
|
||||||
4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */,
|
4C1253692A76D3850004F4B8 /* RelaysChangedNotify.swift */,
|
||||||
4C12536B2A76D4B00004F4B8 /* RepostedNotify.swift */,
|
|
||||||
4C4E137A2A76D5FB00BDD832 /* MuteThreadNotify.swift */,
|
4C4E137A2A76D5FB00BDD832 /* MuteThreadNotify.swift */,
|
||||||
4C4E137C2A76D63600BDD832 /* UnmuteThreadNotify.swift */,
|
4C4E137C2A76D63600BDD832 /* UnmuteThreadNotify.swift */,
|
||||||
B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */,
|
B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */,
|
||||||
@ -2294,7 +2292,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4CE879532996BA0000F758CC /* Detail */,
|
4CE879532996BA0000F758CC /* Detail */,
|
||||||
4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */,
|
|
||||||
4C06670028FC7C5900038D2A /* RelayView.swift */,
|
4C06670028FC7C5900038D2A /* RelayView.swift */,
|
||||||
4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */,
|
4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */,
|
||||||
F7908E91298B0F0700AB113A /* RelayDetailView.swift */,
|
F7908E91298B0F0700AB113A /* RelayDetailView.swift */,
|
||||||
@ -2741,14 +2738,6 @@
|
|||||||
path = DamusNotificationService;
|
path = DamusNotificationService;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
E06336A72B7582D600A88E6B /* Assets */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
E06336A82B7582E000A88E6B /* img_with_location.jpeg */,
|
|
||||||
);
|
|
||||||
path = Assets;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D7CBD1D22B8D21C100BFD889 /* Extensions */ = {
|
D7CBD1D22B8D21C100BFD889 /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -2757,6 +2746,14 @@
|
|||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E06336A72B7582D600A88E6B /* Assets */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E06336A82B7582E000A88E6B /* img_with_location.jpeg */,
|
||||||
|
);
|
||||||
|
path = Assets;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
F71694E82A66221E001F4053 /* Onboarding */ = {
|
F71694E82A66221E001F4053 /* Onboarding */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -3052,6 +3049,7 @@
|
|||||||
4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */,
|
4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */,
|
||||||
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
|
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
|
||||||
4CDD1AE22A6B3074001CD4DF /* NdbTagsIterator.swift in Sources */,
|
4CDD1AE22A6B3074001CD4DF /* NdbTagsIterator.swift in Sources */,
|
||||||
|
5C7389B72B9E692E00781E0A /* MutinyButton.swift in Sources */,
|
||||||
4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
|
4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
|
||||||
D7CB5D512B1174D100AD4105 /* FriendFilter.swift in Sources */,
|
D7CB5D512B1174D100AD4105 /* FriendFilter.swift in Sources */,
|
||||||
D7CBD1D42B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift in Sources */,
|
D7CBD1D42B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift in Sources */,
|
||||||
@ -3109,7 +3107,6 @@
|
|||||||
4C8D00C829DF791C0036AF10 /* CompatibleAttribute.swift in Sources */,
|
4C8D00C829DF791C0036AF10 /* CompatibleAttribute.swift in Sources */,
|
||||||
4C7D09742A0AEF9000943473 /* AlbyGradient.swift in Sources */,
|
4C7D09742A0AEF9000943473 /* AlbyGradient.swift in Sources */,
|
||||||
4C687C272A6039500092C550 /* TestData.swift in Sources */,
|
4C687C272A6039500092C550 /* TestData.swift in Sources */,
|
||||||
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */,
|
|
||||||
50C3E08A2AA8E3F7006A4BC0 /* AVPlayer+Additions.swift in Sources */,
|
50C3E08A2AA8E3F7006A4BC0 /* AVPlayer+Additions.swift in Sources */,
|
||||||
4C198DF229F88C6B004C165C /* BlurHashDecode.swift in Sources */,
|
4C198DF229F88C6B004C165C /* BlurHashDecode.swift in Sources */,
|
||||||
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
|
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
|
||||||
@ -3254,6 +3251,7 @@
|
|||||||
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
||||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
||||||
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
||||||
|
4C94D6432BA5AEFE00C26EFF /* QuoteRepostsView.swift in Sources */,
|
||||||
D7EDED332B12ACAE0018B19C /* DamusUserDefaults.swift in Sources */,
|
D7EDED332B12ACAE0018B19C /* DamusUserDefaults.swift in Sources */,
|
||||||
4CA352AE2A76C1AC003BB08B /* FollowedNotify.swift in Sources */,
|
4CA352AE2A76C1AC003BB08B /* FollowedNotify.swift in Sources */,
|
||||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
||||||
@ -3325,7 +3323,6 @@
|
|||||||
4C32B95E2A9AD44700DC3548 /* FlatBufferObject.swift in Sources */,
|
4C32B95E2A9AD44700DC3548 /* FlatBufferObject.swift in Sources */,
|
||||||
D783A63F2AD4E53D00658DDA /* SuggestedHashtagsView.swift in Sources */,
|
D783A63F2AD4E53D00658DDA /* SuggestedHashtagsView.swift in Sources */,
|
||||||
4C3EA64F28FF59F200C48A62 /* tal.c in Sources */,
|
4C3EA64F28FF59F200C48A62 /* tal.c in Sources */,
|
||||||
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */,
|
|
||||||
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */,
|
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */,
|
||||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
||||||
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */,
|
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */,
|
||||||
@ -3344,6 +3341,7 @@
|
|||||||
4CF0ABD82981980C00D66079 /* Lists.swift in Sources */,
|
4CF0ABD82981980C00D66079 /* Lists.swift in Sources */,
|
||||||
F71694EA2A662232001F4053 /* OnboardingSuggestionsView.swift in Sources */,
|
F71694EA2A662232001F4053 /* OnboardingSuggestionsView.swift in Sources */,
|
||||||
4C12536A2A76D3850004F4B8 /* RelaysChangedNotify.swift in Sources */,
|
4C12536A2A76D3850004F4B8 /* RelaysChangedNotify.swift in Sources */,
|
||||||
|
5C7389B92B9E69ED00781E0A /* MutinyGradient.swift in Sources */,
|
||||||
4C30AC8029A6A53F00E2BD5A /* ProfilePicturesView.swift in Sources */,
|
4C30AC8029A6A53F00E2BD5A /* ProfilePicturesView.swift in Sources */,
|
||||||
D7373BAA2B68A65A00F7783D /* PurpleAccountUpdateNotify.swift in Sources */,
|
D7373BAA2B68A65A00F7783D /* PurpleAccountUpdateNotify.swift in Sources */,
|
||||||
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */,
|
5C6E1DAD2A193EC2008FC15A /* GradientButtonStyle.swift in Sources */,
|
||||||
@ -3416,8 +3414,6 @@
|
|||||||
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
|
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
|
||||||
7527271E2A93FF0100214108 /* Block.swift in Sources */,
|
7527271E2A93FF0100214108 /* Block.swift in Sources */,
|
||||||
4C54AA0729A540BA003E4487 /* NotificationsModel.swift in Sources */,
|
4C54AA0729A540BA003E4487 /* NotificationsModel.swift in Sources */,
|
||||||
4C12536C2A76D4B00004F4B8 /* RepostedNotify.swift in Sources */,
|
|
||||||
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */,
|
|
||||||
4CE4F0F229D4FCFA005914DB /* DebouncedOnChange.swift in Sources */,
|
4CE4F0F229D4FCFA005914DB /* DebouncedOnChange.swift in Sources */,
|
||||||
4C32B9592A9AD44700DC3548 /* Table.swift in Sources */,
|
4C32B9592A9AD44700DC3548 /* Table.swift in Sources */,
|
||||||
4C5D5C9D2A6B2CB40024563C /* AsciiCharacter.swift in Sources */,
|
4C5D5C9D2A6B2CB40024563C /* AsciiCharacter.swift in Sources */,
|
||||||
|
20
damus/Assets.xcassets/iconography/Image.imageset/Contents.json
vendored
Normal file
20
damus/Assets.xcassets/iconography/Image.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
12
damus/Assets.xcassets/mutiny.imageset/Contents.json
vendored
Normal file
12
damus/Assets.xcassets/mutiny.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "mutiny.png",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
damus/Assets.xcassets/mutiny.imageset/mutiny.png
vendored
Normal file
BIN
damus/Assets.xcassets/mutiny.imageset/mutiny.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
15
damus/Components/Gradients/MutinyGradient.swift
Normal file
15
damus/Components/Gradients/MutinyGradient.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// MutinyGradient.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 3/9/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
fileprivate let mutiny_grad_c1 = hex_col(r: 39, g: 95, b: 161)
|
||||||
|
fileprivate let mutiny_grad_c2 = hex_col(r: 13, g: 33, b: 56)
|
||||||
|
fileprivate let mutiny_grad = [mutiny_grad_c2, mutiny_grad_c1]
|
||||||
|
|
||||||
|
let MutinyGradient: LinearGradient =
|
||||||
|
LinearGradient(colors: mutiny_grad, startPoint: .top, endPoint: .bottom)
|
@ -723,7 +723,8 @@ struct ContentView: View {
|
|||||||
nav: self.navigationCoordinator,
|
nav: self.navigationCoordinator,
|
||||||
music: MusicController(onChange: music_changed),
|
music: MusicController(onChange: music_changed),
|
||||||
video: VideoController(),
|
video: VideoController(),
|
||||||
ndb: ndb
|
ndb: ndb,
|
||||||
|
quote_reposts: .init(our_pubkey: pubkey)
|
||||||
)
|
)
|
||||||
|
|
||||||
home.damus_state = self.damus_state!
|
home.damus_state = self.damus_state!
|
||||||
|
@ -16,10 +16,12 @@ enum Zapped {
|
|||||||
class ActionBarModel: ObservableObject {
|
class ActionBarModel: ObservableObject {
|
||||||
@Published var our_like: NostrEvent?
|
@Published var our_like: NostrEvent?
|
||||||
@Published var our_boost: NostrEvent?
|
@Published var our_boost: NostrEvent?
|
||||||
|
@Published var our_quote_repost: NostrEvent?
|
||||||
@Published var our_reply: NostrEvent?
|
@Published var our_reply: NostrEvent?
|
||||||
@Published var our_zap: Zapping?
|
@Published var our_zap: Zapping?
|
||||||
@Published var likes: Int
|
@Published var likes: Int
|
||||||
@Published var boosts: Int
|
@Published var boosts: Int
|
||||||
|
@Published var quote_reposts: Int
|
||||||
@Published private(set) var zaps: Int
|
@Published private(set) var zaps: Int
|
||||||
@Published var zap_total: Int64
|
@Published var zap_total: Int64
|
||||||
@Published var replies: Int
|
@Published var replies: Int
|
||||||
@ -28,7 +30,7 @@ class ActionBarModel: ObservableObject {
|
|||||||
return ActionBarModel(likes: 0, boosts: 0, zaps: 0, zap_total: 0, replies: 0, our_like: nil, our_boost: nil, our_zap: nil, our_reply: nil)
|
return ActionBarModel(likes: 0, boosts: 0, zaps: 0, zap_total: 0, replies: 0, our_like: nil, our_boost: nil, our_zap: nil, our_reply: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(likes: Int = 0, boosts: Int = 0, zaps: Int = 0, zap_total: Int64 = 0, replies: Int = 0, our_like: NostrEvent? = nil, our_boost: NostrEvent? = nil, our_zap: Zapping? = nil, our_reply: NostrEvent? = nil) {
|
init(likes: Int = 0, boosts: Int = 0, zaps: Int = 0, zap_total: Int64 = 0, replies: Int = 0, our_like: NostrEvent? = nil, our_boost: NostrEvent? = nil, our_zap: Zapping? = nil, our_reply: NostrEvent? = nil, our_quote_repost: NostrEvent? = nil, quote_reposts: Int = 0) {
|
||||||
self.likes = likes
|
self.likes = likes
|
||||||
self.boosts = boosts
|
self.boosts = boosts
|
||||||
self.zaps = zaps
|
self.zaps = zaps
|
||||||
@ -38,6 +40,8 @@ class ActionBarModel: ObservableObject {
|
|||||||
self.our_boost = our_boost
|
self.our_boost = our_boost
|
||||||
self.our_zap = our_zap
|
self.our_zap = our_zap
|
||||||
self.our_reply = our_reply
|
self.our_reply = our_reply
|
||||||
|
self.our_quote_repost = our_quote_repost
|
||||||
|
self.quote_reposts = quote_reposts
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(damus: DamusState, evid: NoteId) {
|
func update(damus: DamusState, evid: NoteId) {
|
||||||
@ -45,11 +49,13 @@ class ActionBarModel: ObservableObject {
|
|||||||
self.boosts = damus.boosts.counts[evid] ?? 0
|
self.boosts = damus.boosts.counts[evid] ?? 0
|
||||||
self.zaps = damus.zaps.event_counts[evid] ?? 0
|
self.zaps = damus.zaps.event_counts[evid] ?? 0
|
||||||
self.replies = damus.replies.get_replies(evid)
|
self.replies = damus.replies.get_replies(evid)
|
||||||
|
self.quote_reposts = damus.quote_reposts.counts[evid] ?? 0
|
||||||
self.zap_total = damus.zaps.event_totals[evid] ?? 0
|
self.zap_total = damus.zaps.event_totals[evid] ?? 0
|
||||||
self.our_like = damus.likes.our_events[evid]
|
self.our_like = damus.likes.our_events[evid]
|
||||||
self.our_boost = damus.boosts.our_events[evid]
|
self.our_boost = damus.boosts.our_events[evid]
|
||||||
self.our_zap = damus.zaps.our_zaps[evid]?.first
|
self.our_zap = damus.zaps.our_zaps[evid]?.first
|
||||||
self.our_reply = damus.replies.our_reply(evid)
|
self.our_reply = damus.replies.our_reply(evid)
|
||||||
|
self.our_quote_repost = damus.quote_reposts.our_events[evid]
|
||||||
self.objectWillChange.send()
|
self.objectWillChange.send()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,4 +74,8 @@ class ActionBarModel: ObservableObject {
|
|||||||
var boosted: Bool {
|
var boosted: Bool {
|
||||||
return our_boost != nil
|
return our_boost != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var quoted: Bool {
|
||||||
|
return our_quote_repost != nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,10 @@ struct ContentFilters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension ContentFilters {
|
extension ContentFilters {
|
||||||
|
static func default_filters(damus_state: DamusState) -> ContentFilters {
|
||||||
|
return ContentFilters(filters: ContentFilters.defaults(damus_state: damus_state))
|
||||||
|
}
|
||||||
|
|
||||||
static func defaults(damus_state: DamusState) -> [(NostrEvent) -> Bool] {
|
static func defaults(damus_state: DamusState) -> [(NostrEvent) -> Bool] {
|
||||||
var filters = Array<(NostrEvent) -> Bool>()
|
var filters = Array<(NostrEvent) -> Bool>()
|
||||||
if damus_state.settings.hide_nsfw_tagged_content {
|
if damus_state.settings.hide_nsfw_tagged_content {
|
||||||
|
@ -13,6 +13,7 @@ class DamusState: HeadlessDamusState {
|
|||||||
let keypair: Keypair
|
let keypair: Keypair
|
||||||
let likes: EventCounter
|
let likes: EventCounter
|
||||||
let boosts: EventCounter
|
let boosts: EventCounter
|
||||||
|
let quote_reposts: EventCounter
|
||||||
let contacts: Contacts
|
let contacts: Contacts
|
||||||
let mutelist_manager: MutelistManager
|
let mutelist_manager: MutelistManager
|
||||||
let profiles: Profiles
|
let profiles: Profiles
|
||||||
@ -36,7 +37,7 @@ class DamusState: HeadlessDamusState {
|
|||||||
let ndb: Ndb
|
let ndb: Ndb
|
||||||
var purple: DamusPurple
|
var purple: DamusPurple
|
||||||
|
|
||||||
init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [String], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil) {
|
init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [String], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter) {
|
||||||
self.pool = pool
|
self.pool = pool
|
||||||
self.keypair = keypair
|
self.keypair = keypair
|
||||||
self.likes = likes
|
self.likes = likes
|
||||||
@ -66,6 +67,7 @@ class DamusState: HeadlessDamusState {
|
|||||||
settings: settings,
|
settings: settings,
|
||||||
keypair: keypair
|
keypair: keypair
|
||||||
)
|
)
|
||||||
|
self.quote_reposts = quote_reposts
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
@ -129,7 +131,8 @@ class DamusState: HeadlessDamusState {
|
|||||||
nav: NavigationCoordinator(),
|
nav: NavigationCoordinator(),
|
||||||
music: nil,
|
music: nil,
|
||||||
video: VideoController(),
|
video: VideoController(),
|
||||||
ndb: .empty
|
ndb: .empty,
|
||||||
|
quote_reposts: .init(our_pubkey: empty_pub)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,25 +7,62 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
class EventsModel: ObservableObject {
|
class EventsModel: ObservableObject {
|
||||||
let state: DamusState
|
let state: DamusState
|
||||||
let target: NoteId
|
let target: NoteId
|
||||||
let kind: NostrKind
|
let kind: QueryKind
|
||||||
let sub_id = UUID().uuidString
|
let sub_id = UUID().uuidString
|
||||||
let profiles_id = UUID().uuidString
|
let profiles_id = UUID().uuidString
|
||||||
|
var events: EventHolder
|
||||||
|
@Published var loading: Bool
|
||||||
|
|
||||||
@Published var events: [NostrEvent] = []
|
enum QueryKind {
|
||||||
|
case kind(NostrKind)
|
||||||
|
case quotes
|
||||||
|
}
|
||||||
|
|
||||||
init(state: DamusState, target: NoteId, kind: NostrKind) {
|
init(state: DamusState, target: NoteId, kind: NostrKind) {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.target = target
|
self.target = target
|
||||||
self.kind = kind
|
self.kind = .kind(kind)
|
||||||
|
self.loading = true
|
||||||
|
self.events = EventHolder(on_queue: { ev in
|
||||||
|
preload_events(state: state, events: [ev])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
init(state: DamusState, target: NoteId, query: EventsModel.QueryKind) {
|
||||||
|
self.state = state
|
||||||
|
self.target = target
|
||||||
|
self.kind = query
|
||||||
|
self.loading = true
|
||||||
|
self.events = EventHolder(on_queue: { ev in
|
||||||
|
preload_events(state: state, events: [ev])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func quotes(state: DamusState, target: NoteId) -> EventsModel {
|
||||||
|
EventsModel(state: state, target: target, query: .quotes)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func reposts(state: DamusState, target: NoteId) -> EventsModel {
|
||||||
|
EventsModel(state: state, target: target, kind: .boost)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func likes(state: DamusState, target: NoteId) -> EventsModel {
|
||||||
|
EventsModel(state: state, target: target, kind: .like)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func get_filter() -> NostrFilter {
|
private func get_filter() -> NostrFilter {
|
||||||
var filter = NostrFilter(kinds: [kind])
|
var filter: NostrFilter
|
||||||
|
switch kind {
|
||||||
|
case .kind(let k):
|
||||||
|
filter = NostrFilter(kinds: [k])
|
||||||
filter.referenced_ids = [target]
|
filter.referenced_ids = [target]
|
||||||
|
case .quotes:
|
||||||
|
filter = NostrFilter(kinds: [.text])
|
||||||
|
filter.quotes = [target]
|
||||||
|
}
|
||||||
filter.limit = 500
|
filter.limit = 500
|
||||||
return filter
|
return filter
|
||||||
}
|
}
|
||||||
@ -41,18 +78,14 @@ class EventsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func handle_event(relay_id: String, ev: NostrEvent) {
|
private func handle_event(relay_id: String, ev: NostrEvent) {
|
||||||
guard ev.kind == kind.rawValue,
|
if events.insert(ev) {
|
||||||
ev.referenced_ids.last == target else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { a, b in a.created_at < b.created_at } ) {
|
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_nostr_event(relay_id: String, ev: NostrConnectionEvent) {
|
func handle_nostr_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||||
guard case .nostr_event(let nev) = ev else {
|
guard case .nostr_event(let nev) = ev, nev.subid == self.sub_id
|
||||||
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,10 +99,11 @@ class EventsModel: ObservableObject {
|
|||||||
case .auth:
|
case .auth:
|
||||||
break
|
break
|
||||||
case .eose:
|
case .eose:
|
||||||
|
self.loading = false
|
||||||
guard let txn = NdbTxn(ndb: self.state.ndb) else {
|
guard let txn = NdbTxn(ndb: self.state.ndb) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
load_profiles(context: "events_model", profiles_subid: profiles_id, relay_id: relay_id, load: .from_events(events), damus_state: state, txn: txn)
|
load_profiles(context: "events_model", profiles_subid: profiles_id, relay_id: relay_id, load: .from_events(events.all_events), damus_state: state, txn: txn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,12 +347,19 @@ class HomeModel {
|
|||||||
case .already_counted:
|
case .already_counted:
|
||||||
break
|
break
|
||||||
case .success(let n):
|
case .success(let n):
|
||||||
let boosted = Counted(event: ev, id: e, total: n)
|
|
||||||
notify(.reposted(boosted))
|
|
||||||
notify(.update_stats(note_id: e))
|
notify(.update_stats(note_id: e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handle_quote_repost_event(_ ev: NostrEvent, target: NoteId) {
|
||||||
|
switch damus_state.quote_reposts.add_event(ev, target: target) {
|
||||||
|
case .already_counted:
|
||||||
|
break
|
||||||
|
case .success(let n):
|
||||||
|
notify(.update_stats(note_id: target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handle_like_event(_ ev: NostrEvent) {
|
func handle_like_event(_ ev: NostrEvent) {
|
||||||
guard let e = ev.last_refid() else {
|
guard let e = ev.last_refid() else {
|
||||||
// no id ref? invalid like event
|
// no id ref? invalid like event
|
||||||
@ -672,6 +679,10 @@ class HomeModel {
|
|||||||
damus_state.replies.count_replies(ev, keypair: self.damus_state.keypair)
|
damus_state.replies.count_replies(ev, keypair: self.damus_state.keypair)
|
||||||
damus_state.events.insert(ev)
|
damus_state.events.insert(ev)
|
||||||
|
|
||||||
|
if let quoted_event = ev.referenced_quote_ids.first {
|
||||||
|
handle_quote_repost_event(ev, target: quoted_event.note_id)
|
||||||
|
}
|
||||||
|
|
||||||
if sub_id == home_subid {
|
if sub_id == home_subid {
|
||||||
insert_home_event(ev)
|
insert_home_event(ev)
|
||||||
} else if sub_id == notifications_subid {
|
} else if sub_id == notifications_subid {
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// LikesModel.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by William Casarin on 2023-01-11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
final class ReactionsModel: EventsModel {
|
|
||||||
|
|
||||||
init(state: DamusState, target: NoteId) {
|
|
||||||
super.init(state: state, target: target, kind: .like)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// RepostsModel.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by Terry Yiu on 1/22/23.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
final class RepostsModel: EventsModel {
|
|
||||||
|
|
||||||
init(state: DamusState, target: NoteId) {
|
|
||||||
super.init(state: state, target: target, kind: .boost)
|
|
||||||
}
|
|
||||||
}
|
|
@ -56,6 +56,7 @@ class ThreadModel: ObservableObject {
|
|||||||
|
|
||||||
func subscribe() {
|
func subscribe() {
|
||||||
var meta_events = NostrFilter()
|
var meta_events = NostrFilter()
|
||||||
|
var quote_events = NostrFilter()
|
||||||
var event_filter = NostrFilter()
|
var event_filter = NostrFilter()
|
||||||
var ref_events = NostrFilter()
|
var ref_events = NostrFilter()
|
||||||
|
|
||||||
@ -74,11 +75,14 @@ class ThreadModel: ObservableObject {
|
|||||||
kinds.append(.like)
|
kinds.append(.like)
|
||||||
}
|
}
|
||||||
meta_events.kinds = kinds
|
meta_events.kinds = kinds
|
||||||
|
|
||||||
meta_events.limit = 1000
|
meta_events.limit = 1000
|
||||||
|
|
||||||
|
quote_events.kinds = [.text]
|
||||||
|
quote_events.quotes = [event.id]
|
||||||
|
quote_events.limit = 1000
|
||||||
|
|
||||||
let base_filters = [event_filter, ref_events]
|
let base_filters = [event_filter, ref_events]
|
||||||
let meta_filters = [meta_events]
|
let meta_filters = [meta_events, quote_events]
|
||||||
|
|
||||||
print("subscribing to thread \(event.id) with sub_id \(base_subid)")
|
print("subscribing to thread \(event.id) with sub_id \(base_subid)")
|
||||||
damus_state.pool.subscribe(sub_id: base_subid, filters: base_filters, handler: handle_event)
|
damus_state.pool.subscribe(sub_id: base_subid, filters: base_filters, handler: handle_event)
|
||||||
@ -90,7 +94,7 @@ class ThreadModel: ObservableObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let the_ev = damus_state.events.upsert(ev)
|
damus_state.events.upsert(ev)
|
||||||
damus_state.replies.count_replies(ev, keypair: keypair)
|
damus_state.replies.count_replies(ev, keypair: keypair)
|
||||||
damus_state.events.add_replies(ev: ev, keypair: keypair)
|
damus_state.events.add_replies(ev: ev, keypair: keypair)
|
||||||
|
|
||||||
@ -111,9 +115,15 @@ class ThreadModel: ObservableObject {
|
|||||||
|
|
||||||
}
|
}
|
||||||
} else if ev.is_textlike {
|
} else if ev.is_textlike {
|
||||||
|
// handle thread quote reposts, we just count them instead of
|
||||||
|
// adding them to the thread
|
||||||
|
if let target = ev.is_quote_repost, target == self.event.id {
|
||||||
|
//let _ = self.damus_state.quote_reposts.add_event(ev, target: target)
|
||||||
|
} else {
|
||||||
self.add_event(ev, keypair: damus_state.keypair)
|
self.add_event(ev, keypair: damus_state.keypair)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guard done, let sub_id, subids.contains(sub_id) else {
|
guard done, let sub_id, subids.contains(sub_id) else {
|
||||||
return
|
return
|
||||||
|
@ -41,7 +41,7 @@ struct QuoteId: IdType, TagKey, TagConvertible {
|
|||||||
self.id = data
|
self.id = data
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refer to this QuoteId as a NoteId
|
/// The note id being quoted
|
||||||
var note_id: NoteId {
|
var note_id: NoteId {
|
||||||
NoteId(self.id)
|
NoteId(self.id)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ struct NostrFilter: Codable, Equatable {
|
|||||||
var authors: [Pubkey]?
|
var authors: [Pubkey]?
|
||||||
var hashtag: [String]?
|
var hashtag: [String]?
|
||||||
var parameter: [String]?
|
var parameter: [String]?
|
||||||
|
var quotes: [NoteId]?
|
||||||
|
|
||||||
private enum CodingKeys : String, CodingKey {
|
private enum CodingKeys : String, CodingKey {
|
||||||
case ids
|
case ids
|
||||||
@ -26,13 +27,14 @@ struct NostrFilter: Codable, Equatable {
|
|||||||
case pubkeys = "#p"
|
case pubkeys = "#p"
|
||||||
case hashtag = "#t"
|
case hashtag = "#t"
|
||||||
case parameter = "#d"
|
case parameter = "#d"
|
||||||
|
case quotes = "#q"
|
||||||
case since
|
case since
|
||||||
case until
|
case until
|
||||||
case authors
|
case authors
|
||||||
case limit
|
case limit
|
||||||
}
|
}
|
||||||
|
|
||||||
init(ids: [NoteId]? = nil, kinds: [NostrKind]? = nil, referenced_ids: [NoteId]? = nil, pubkeys: [Pubkey]? = nil, since: UInt32? = nil, until: UInt32? = nil, limit: UInt32? = nil, authors: [Pubkey]? = nil, hashtag: [String]? = nil) {
|
init(ids: [NoteId]? = nil, kinds: [NostrKind]? = nil, referenced_ids: [NoteId]? = nil, pubkeys: [Pubkey]? = nil, since: UInt32? = nil, until: UInt32? = nil, limit: UInt32? = nil, authors: [Pubkey]? = nil, hashtag: [String]? = nil, quotes: [NoteId]? = nil) {
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
self.kinds = kinds
|
self.kinds = kinds
|
||||||
self.referenced_ids = referenced_ids
|
self.referenced_ids = referenced_ids
|
||||||
@ -42,6 +44,7 @@ struct NostrFilter: Codable, Equatable {
|
|||||||
self.limit = limit
|
self.limit = limit
|
||||||
self.authors = authors
|
self.authors = authors
|
||||||
self.hashtag = hashtag
|
self.hashtag = hashtag
|
||||||
|
self.quotes = quotes
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func copy(from: NostrFilter) -> NostrFilter {
|
public static func copy(from: NostrFilter) -> NostrFilter {
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
//
|
|
||||||
// BoostedNotify.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by William Casarin on 2023-07-30.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct RepostedNotify: Notify {
|
|
||||||
typealias Payload = Counted
|
|
||||||
var payload: Payload
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NotifyHandler {
|
|
||||||
static var reposted: NotifyHandler<RepostedNotify> {
|
|
||||||
.init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Notifications {
|
|
||||||
static func reposted(_ counts: Counted) -> Notifications<RepostedNotify> {
|
|
||||||
.init(.init(payload: counts))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -92,7 +92,9 @@ var test_damus_state: DamusState = ({
|
|||||||
nav: .init(),
|
nav: .init(),
|
||||||
music: .init(onChange: {_ in }),
|
music: .init(onChange: {_ in }),
|
||||||
video: .init(),
|
video: .init(),
|
||||||
ndb: ndb)
|
ndb: ndb,
|
||||||
|
quote_reposts: .init(our_pubkey: our_pubkey)
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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)
|
||||||
|
@ -31,8 +31,9 @@ enum Route: Hashable {
|
|||||||
case SearchSettings(settings: UserSettingsStore)
|
case SearchSettings(settings: UserSettingsStore)
|
||||||
case DeveloperSettings(settings: UserSettingsStore)
|
case DeveloperSettings(settings: UserSettingsStore)
|
||||||
case Thread(thread: ThreadModel)
|
case Thread(thread: ThreadModel)
|
||||||
case Reposts(reposts: RepostsModel)
|
case Reposts(reposts: EventsModel)
|
||||||
case Reactions(reactions: ReactionsModel)
|
case QuoteReposts(quotes: EventsModel)
|
||||||
|
case Reactions(reactions: EventsModel)
|
||||||
case Zaps(target: ZapTarget)
|
case Zaps(target: ZapTarget)
|
||||||
case Search(search: SearchModel)
|
case Search(search: SearchModel)
|
||||||
case EULA
|
case EULA
|
||||||
@ -53,7 +54,7 @@ enum Route: Hashable {
|
|||||||
case .Followers(let followers):
|
case .Followers(let followers):
|
||||||
FollowersView(damus_state: damusState, followers: followers)
|
FollowersView(damus_state: damusState, followers: followers)
|
||||||
case .Relay(let relay, let showActionButtons):
|
case .Relay(let relay, let showActionButtons):
|
||||||
RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons)
|
RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons, recommended: false)
|
||||||
case .RelayDetail(let relay, let metadata):
|
case .RelayDetail(let relay, let metadata):
|
||||||
RelayDetailView(state: damusState, relay: relay, nip11: metadata)
|
RelayDetailView(state: damusState, relay: relay, nip11: metadata)
|
||||||
case .Following(let following):
|
case .Following(let following):
|
||||||
@ -92,6 +93,8 @@ enum Route: Hashable {
|
|||||||
ThreadView(state: damusState, thread: thread)
|
ThreadView(state: damusState, thread: thread)
|
||||||
case .Reposts(let reposts):
|
case .Reposts(let reposts):
|
||||||
RepostsView(damus_state: damusState, model: reposts)
|
RepostsView(damus_state: damusState, model: reposts)
|
||||||
|
case .QuoteReposts(let quote_reposts):
|
||||||
|
QuoteRepostsView(damus_state: damusState, model: quote_reposts)
|
||||||
case .Reactions(let reactions):
|
case .Reactions(let reactions):
|
||||||
ReactionsView(damus_state: damusState, model: reactions)
|
ReactionsView(damus_state: damusState, model: reactions)
|
||||||
case .Zaps(let target):
|
case .Zaps(let target):
|
||||||
@ -178,6 +181,9 @@ enum Route: Hashable {
|
|||||||
case .Reposts(let reposts):
|
case .Reposts(let reposts):
|
||||||
hasher.combine("reposts")
|
hasher.combine("reposts")
|
||||||
hasher.combine(reposts.target)
|
hasher.combine(reposts.target)
|
||||||
|
case .QuoteReposts(let evs_model):
|
||||||
|
hasher.combine("quote_reposts")
|
||||||
|
hasher.combine(evs_model.events.events.count)
|
||||||
case .Zaps(let target):
|
case .Zaps(let target):
|
||||||
hasher.combine("zaps")
|
hasher.combine("zaps")
|
||||||
hasher.combine(target.id)
|
hasher.combine(target.id)
|
||||||
|
@ -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(value: Route.Reposts(reposts: RepostsModel(state: state, target: target))) {
|
NavigationLink(value: Route.Reposts(reposts: .reposts(state: state, target: target))) {
|
||||||
let nounString = pluralizedString(key: "reposts_count", count: bar.boosts)
|
let nounString = pluralizedString(key: "reposts_count", count: bar.boosts)
|
||||||
let noun = Text(nounString).foregroundColor(.gray)
|
let noun = Text(nounString).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,8 +33,17 @@ struct EventDetailBar: View {
|
|||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bar.quote_reposts > 0 {
|
||||||
|
NavigationLink(value: Route.QuoteReposts(quotes: .quotes(state: state, target: target))) {
|
||||||
|
let nounString = pluralizedString(key: "quoted_reposts_count", count: bar.quote_reposts)
|
||||||
|
let noun = Text(nounString).foregroundColor(.gray)
|
||||||
|
Text("\(Text(verbatim: bar.quote_reposts.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many quoted reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
}
|
||||||
|
|
||||||
if bar.likes > 0 && !state.settings.onlyzaps_mode {
|
if bar.likes > 0 && !state.settings.onlyzaps_mode {
|
||||||
NavigationLink(value: Route.Reactions(reactions: ReactionsModel(state: state, target: target))) {
|
NavigationLink(value: Route.Reactions(reactions: .likes(state: state, target: target))) {
|
||||||
let nounString = pluralizedString(key: "reactions_count", count: bar.likes)
|
let nounString = pluralizedString(key: "reactions_count", count: bar.likes)
|
||||||
let noun = Text(nounString).foregroundColor(.gray)
|
let noun = Text(nounString).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'.")
|
||||||
|
@ -23,16 +23,15 @@ struct AlbyButton: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Image("alby")
|
Image("alby")
|
||||||
|
|
||||||
Text("Attach Alby Wallet", comment: "Button to attach an Alby Wallet, a service that provides a Lightning wallet for zapping sats. Alby is the name of the service and should not be translated.")
|
Text("Connect to Alby Wallet", comment: "Button to attach an Alby Wallet, a service that provides a Lightning wallet for zapping sats. Alby is the name of the service and should not be translated.")
|
||||||
|
.padding()
|
||||||
}
|
}
|
||||||
.offset(x: -25)
|
.frame(minWidth: 300, maxWidth: .infinity, alignment: .center)
|
||||||
.frame(minWidth: 300, maxWidth: .infinity, minHeight: 50, maxHeight: 50, alignment: .center)
|
|
||||||
.foregroundColor(DamusColors.black)
|
.foregroundColor(DamusColors.black)
|
||||||
.background {
|
.background {
|
||||||
RoundedRectangle(cornerRadius: 24)
|
RoundedRectangle(cornerRadius: 12)
|
||||||
.fill(AlbyGradient, strokeBorder: colorScheme == .light ? DamusColors.black : DamusColors.white, lineWidth: 2)
|
.fill(AlbyGradient, strokeBorder: colorScheme == .light ? DamusColors.black.opacity(0.2) : DamusColors.white, lineWidth: 1)
|
||||||
}
|
}
|
||||||
.padding(EdgeInsets(top: 10, leading: 50, bottom: 25, trailing: 50))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
47
damus/Views/Buttons/MutinyButton.swift
Normal file
47
damus/Views/Buttons/MutinyButton.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// MutinyButton.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 3/9/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MutinyButton: View {
|
||||||
|
let action: () -> ()
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
init(action: @escaping () -> ()) {
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: {
|
||||||
|
action()
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image("mutiny")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 45, height: 45)
|
||||||
|
|
||||||
|
Text("Connect to Mutiny Wallet", comment: "Button to attach an Mutiny Wallet, a service that provides a Lightning wallet for zapping sats. Mutiny is the name of the service and should not be translated.")
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, alignment: .center)
|
||||||
|
.foregroundColor(DamusColors.white)
|
||||||
|
.background {
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(MutinyGradient, strokeBorder: colorScheme == .light ? DamusColors.black.opacity(0.2) : DamusColors.white.opacity(0.2), lineWidth: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MutinyButton_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
MutinyButton(action: {
|
||||||
|
print("mutiny button")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,10 @@ struct SelectedEventView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProxyView(event: event)
|
||||||
|
.padding(.top, 5)
|
||||||
|
.padding(.horizontal)
|
||||||
|
|
||||||
EventBody(damus_state: damus, event: event, size: size, options: [.wide])
|
EventBody(damus_state: damus, event: event, size: size, options: [.wide])
|
||||||
|
|
||||||
Mention
|
Mention
|
||||||
|
@ -9,14 +9,14 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ReactionsView: View {
|
struct ReactionsView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@StateObject var model: ReactionsModel
|
@StateObject var model: EventsModel
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(model.events, id: \.id) { ev in
|
ForEach(model.events.events, id: \.id) { ev in
|
||||||
ReactionView(damus_state: damus_state, reaction: ev)
|
ReactionView(damus_state: damus_state, reaction: ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +38,6 @@ struct ReactionsView: View {
|
|||||||
struct ReactionsView_Previews: PreviewProvider {
|
struct ReactionsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let state = test_damus_state
|
let state = test_damus_state
|
||||||
ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: test_note.id))
|
ReactionsView(damus_state: state, model: .likes(state: state, target: test_note.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
//
|
|
||||||
// RecommendedRelayView.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by William Casarin on 2022-12-29.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct RecommendedRelayView: View {
|
|
||||||
let damus: DamusState
|
|
||||||
let relay: String
|
|
||||||
let add_button: Bool
|
|
||||||
let user_recommended: Bool
|
|
||||||
|
|
||||||
@ObservedObject private var model_cache: RelayModelCache
|
|
||||||
|
|
||||||
init(damus: DamusState, relay: String, add_button: Bool = true, user_recommended: Bool = false) {
|
|
||||||
self.damus = damus
|
|
||||||
self.relay = relay
|
|
||||||
self.add_button = add_button
|
|
||||||
self.user_recommended = user_recommended
|
|
||||||
self.model_cache = damus.relay_model_cache
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
let meta = model_cache.model(with_relay_id: relay)?.metadata
|
|
||||||
|
|
||||||
if user_recommended {
|
|
||||||
HStack {
|
|
||||||
RelayPicView(relay: relay, icon: meta?.icon, size: 50, highlight: .none, disable_animation: false)
|
|
||||||
.padding(.horizontal, 5)
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack {
|
|
||||||
Text(meta?.name ?? relay)
|
|
||||||
.font(.headline)
|
|
||||||
.padding(.bottom, 2)
|
|
||||||
|
|
||||||
RelayType(is_paid: damus.relay_model_cache.model(with_relay_id: relay)?.metadata.is_paid ?? false)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(relay)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.gray)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let keypair = damus.keypair.to_full() {
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
if damus.pool.get_relay(relay) == nil {
|
|
||||||
AddButton(keypair: keypair)
|
|
||||||
} else {
|
|
||||||
Image(systemName: "checkmark.circle")
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 30, height: 30)
|
|
||||||
.foregroundColor(DamusColors.success)
|
|
||||||
.padding(.trailing, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VStack {
|
|
||||||
RelayPicView(relay: relay, icon: meta?.icon, size: 70, highlight: .none, disable_animation: false)
|
|
||||||
if let meta = damus.relay_model_cache.model(with_relay_id: relay)?.metadata {
|
|
||||||
NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta)){
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
.opacity(0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack {
|
|
||||||
Text(meta?.name ?? relay)
|
|
||||||
.lineLimit(1)
|
|
||||||
.frame(maxWidth: 150)
|
|
||||||
.padding(.vertical, 5)
|
|
||||||
}
|
|
||||||
.contextMenu {
|
|
||||||
CopyAction(relay: relay)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let keypair = damus.keypair.to_full() {
|
|
||||||
AddButton(keypair: keypair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CopyAction(relay: String) -> some View {
|
|
||||||
Button {
|
|
||||||
UIPasteboard.general.setValue(relay, forPasteboardType: "public.plain-text")
|
|
||||||
} label: {
|
|
||||||
Label(NSLocalizedString("Copy", comment: "Button to copy a relay server address."), image: "copy")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddButton(keypair: FullKeypair) -> some View {
|
|
||||||
Button(action: {
|
|
||||||
add_action(keypair: keypair)
|
|
||||||
}) {
|
|
||||||
Text(NSLocalizedString("Add", comment: "Button to add relay server to list."))
|
|
||||||
.padding(10)
|
|
||||||
}
|
|
||||||
.buttonStyle(NeutralButtonStyle())
|
|
||||||
}
|
|
||||||
|
|
||||||
func add_action(keypair: FullKeypair) {
|
|
||||||
guard let ev_before_add = damus.contacts.event else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let relay_url = RelayURL(relay),
|
|
||||||
let ev_after_add = add_relay(ev: ev_before_add, keypair: keypair, current_relays: damus.pool.our_descriptors, relay: relay_url, info: .rw) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
process_contact_event(state: damus, ev: ev_after_add)
|
|
||||||
damus.postbox.send(ev_after_add)
|
|
||||||
|
|
||||||
if let relay_metadata = make_relay_metadata(relays: damus.pool.our_descriptors, keypair: keypair) {
|
|
||||||
damus.postbox.send(relay_metadata)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RecommendedRelayView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
RecommendedRelayView(damus: test_damus_state, relay: "wss://relay.damus.io", user_recommended: true)
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,156 +7,83 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
enum RelayTab: Int, CaseIterable{
|
||||||
|
case myRelays = 0
|
||||||
|
case recommended
|
||||||
|
|
||||||
|
var title: String{
|
||||||
|
switch self {
|
||||||
|
case .myRelays:
|
||||||
|
return "My relays"
|
||||||
|
case .recommended:
|
||||||
|
return "Recommended"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RelayConfigView: View {
|
struct RelayConfigView: View {
|
||||||
let state: DamusState
|
let state: DamusState
|
||||||
@State var relays: [RelayDescriptor]
|
@State var relays: [RelayDescriptor]
|
||||||
@State private var showActionButtons = false
|
@State private var showActionButtons = false
|
||||||
@State var show_add_relay: Bool = false
|
@State var show_add_relay: Bool = false
|
||||||
@SceneStorage("RelayConfigView.show_recommended") var show_recommended : Bool = true
|
@State var selectedTab = 0
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
init(state: DamusState) {
|
init(state: DamusState) {
|
||||||
self.state = state
|
self.state = state
|
||||||
_relays = State(initialValue: state.pool.our_descriptors)
|
_relays = State(initialValue: state.pool.our_descriptors)
|
||||||
|
UITabBar.appearance().isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var recommended: [RelayDescriptor] {
|
var recommended: [RelayDescriptor] {
|
||||||
let rs: [RelayDescriptor] = []
|
let rs: [RelayDescriptor] = []
|
||||||
let recommended_relay_addresses = get_default_bootstrap_relays()
|
let recommended_relay_addresses = get_default_bootstrap_relays()
|
||||||
return recommended_relay_addresses.reduce(into: rs) { xs, x in
|
return recommended_relay_addresses.reduce(into: rs) { xs, x in
|
||||||
if state.pool.get_relay(x) == nil, let url = RelayURL(x) {
|
if let url = RelayURL(x) {
|
||||||
xs.append(RelayDescriptor(url: url, info: .rw))
|
xs.append(RelayDescriptor(url: url, info: .rw))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MainContent
|
NavigationView {
|
||||||
.onReceive(handle_notify(.relays_changed)) { _ in
|
ZStack(alignment: .bottom){
|
||||||
self.relays = state.pool.our_descriptors
|
TabView(selection: $selectedTab) {
|
||||||
}
|
RelayList(title: "My Relays", relayList: relays, recommended: false)
|
||||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
.tag(0)
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var MainContent: some View {
|
RelayList(title: "Recommended", relayList: recommended, recommended: true)
|
||||||
VStack {
|
.tag(1)
|
||||||
Divider()
|
|
||||||
|
|
||||||
if showActionButtons && !show_recommended {
|
|
||||||
VStack {
|
|
||||||
Button(action: {
|
|
||||||
withAnimation(.easeOut(duration: 0.2)) {
|
|
||||||
show_recommended.toggle()
|
|
||||||
}
|
}
|
||||||
}) {
|
ZStack{
|
||||||
Text("Show recommended relays", comment: "Button to show recommended relays.")
|
|
||||||
.foregroundStyle(DamusLightGradient.gradient)
|
|
||||||
.padding(10)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 15)
|
|
||||||
.stroke(DamusLightGradient.gradient)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.top, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if recommended.count > 0 && show_recommended {
|
|
||||||
VStack {
|
|
||||||
HStack(alignment: .top) {
|
|
||||||
Spacer()
|
|
||||||
Button(action: {
|
|
||||||
withAnimation(.easeOut(duration: 0.2)) {
|
|
||||||
show_recommended.toggle()
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Image(systemName: "xmark.circle")
|
|
||||||
.font(.system(size: 18))
|
|
||||||
.foregroundStyle(DamusLightGradient.gradient)
|
|
||||||
}
|
|
||||||
.padding([.top, .trailing], 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("Recommended relays", comment: "Title for view of recommended relays.")
|
|
||||||
.foregroundStyle(DamusLightGradient.gradient)
|
|
||||||
.padding(10)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 15)
|
|
||||||
.stroke(DamusLightGradient.gradient)
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollView(.horizontal) {
|
|
||||||
HStack(spacing: 20) {
|
|
||||||
ForEach(recommended, id: \.url) { r in
|
|
||||||
RecommendedRelayView(damus: state, relay: r.url.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 30)
|
|
||||||
.padding(.vertical, 5)
|
|
||||||
}
|
|
||||||
.scrollIndicators(.hidden)
|
|
||||||
.mask(
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
LinearGradient(gradient: Gradient(colors: [Color.clear, Color.white]), startPoint: .leading, endPoint: .trailing)
|
|
||||||
.frame(width: 30)
|
|
||||||
|
|
||||||
Rectangle()
|
|
||||||
.fill(Color.white)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
|
|
||||||
LinearGradient(gradient: Gradient(colors: [Color.white, Color.clear]), startPoint: .leading, endPoint: .trailing)
|
|
||||||
.frame(width: 30)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
.frame(minWidth: 250, maxWidth: .infinity, minHeight: 250, alignment: .center)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.fill(DamusLightGradient.gradient.opacity(0.15), strokeBorder: DamusLightGradient.gradient, lineWidth: 1)
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack{
|
HStack{
|
||||||
Text(NSLocalizedString("My Relays", comment: "Section title for relay servers that the user is connected to."))
|
ForEach((RelayTab.allCases), id: \.self){ item in
|
||||||
.font(.system(size: 32, weight: .bold))
|
Button{
|
||||||
|
selectedTab = item.rawValue
|
||||||
Spacer()
|
} label: {
|
||||||
|
CustomTabItem(title: item.title, isActive: (selectedTab == item.rawValue))
|
||||||
Button(action: {
|
|
||||||
show_add_relay.toggle()
|
|
||||||
}) {
|
|
||||||
HStack {
|
|
||||||
Text(verbatim: "Add relay")
|
|
||||||
.padding(10)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(NeutralButtonStyle())
|
|
||||||
}
|
}
|
||||||
.padding(25)
|
|
||||||
|
|
||||||
List(Array(relays), id: \.url) { relay in
|
|
||||||
RelayView(state: state, relay: relay.url.id, showActionButtons: $showActionButtons)
|
|
||||||
}
|
}
|
||||||
.listStyle(PlainListStyle())
|
.frame(width: 235, height: 35)
|
||||||
|
.background(.damusNeutral3)
|
||||||
|
.cornerRadius(30)
|
||||||
|
.padding(.horizontal, 26)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(NSLocalizedString("Relays", comment: "Title of relays view"))
|
.navigationTitle(NSLocalizedString("Relays", comment: "Title of relays view"))
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.navigationBarBackButtonHidden(true)
|
||||||
|
.navigationBarItems(leading: BackNav())
|
||||||
.sheet(isPresented: $show_add_relay, onDismiss: { self.show_add_relay = false }) {
|
.sheet(isPresented: $show_add_relay, onDismiss: { self.show_add_relay = false }) {
|
||||||
if #available(iOS 16.0, *) {
|
|
||||||
AddRelayView(state: state)
|
AddRelayView(state: state)
|
||||||
.presentationDetents([.height(300)])
|
.presentationDetents([.height(300)])
|
||||||
.presentationDragIndicator(.visible)
|
.presentationDragIndicator(.visible)
|
||||||
} else {
|
|
||||||
AddRelayView(state: state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
if state.keypair.privkey != nil {
|
if state.keypair.privkey != nil && selectedTab == 0 {
|
||||||
if showActionButtons {
|
if showActionButtons {
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
@ -172,6 +99,65 @@ struct RelayConfigView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onReceive(handle_notify(.relays_changed)) { _ in
|
||||||
|
self.relays = state.pool.our_descriptors
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
notify(.display_tabbar(false))
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
notify(.display_tabbar(true))
|
||||||
|
}
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RelayList(title: String, relayList: [RelayDescriptor], recommended: Bool) -> some View {
|
||||||
|
ScrollView(showsIndicators: false) {
|
||||||
|
HStack {
|
||||||
|
Text(NSLocalizedString(title, comment: "Section title for type of relay server list"))
|
||||||
|
.font(.system(size: 32, weight: .bold))
|
||||||
|
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if state.keypair.privkey != nil {
|
||||||
|
Button(action: {
|
||||||
|
show_add_relay.toggle()
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Text(verbatim: "Add relay")
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(NeutralButtonStyle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, 5)
|
||||||
|
|
||||||
|
ForEach(relayList, id: \.url) { relay in
|
||||||
|
Group {
|
||||||
|
RelayView(state: state, relay: relay.url.id, showActionButtons: $showActionButtons, recommended: recommended)
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
.padding(25)
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RelayConfigView{
|
||||||
|
func CustomTabItem(title: String, isActive: Bool) -> some View {
|
||||||
|
HStack {
|
||||||
|
Text(title)
|
||||||
|
.font(.system(size: 12, weight: isActive ? .bold : .regular))
|
||||||
|
.foregroundColor(isActive ? .damusAdaptableBlack : .damusAdaptableBlack.opacity(0.7))
|
||||||
|
}
|
||||||
|
.frame(width: 110, height: 30)
|
||||||
|
.background(isActive ? .damusAdaptableWhite.opacity(0.9) : .clear)
|
||||||
|
.cornerRadius(30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,8 @@ struct RelayDetailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
|
ZStack {
|
||||||
Group {
|
Group {
|
||||||
Form {
|
Form {
|
||||||
if let keypair = state.keypair.to_full() {
|
if let keypair = state.keypair.to_full() {
|
||||||
@ -159,11 +161,16 @@ struct RelayDetailView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.onReceive(handle_notify(.switched_timeline)) { notif in
|
.onReceive(handle_notify(.switched_timeline)) { notif in
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
.navigationTitle(nip11?.name ?? relay)
|
.navigationTitle(nip11?.name ?? relay)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.navigationBarBackButtonHidden(true)
|
||||||
|
.navigationBarItems(leading: BackNav())
|
||||||
|
.ignoresSafeArea(.all)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func nipsList(nips: [Int]) -> AttributedString {
|
private func nipsList(nips: [Int]) -> AttributedString {
|
||||||
|
@ -61,7 +61,7 @@ struct InnerRelayPicView: View {
|
|||||||
}
|
}
|
||||||
.frame(width: size, height: size)
|
.frame(width: size, height: size)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 15))
|
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||||
.overlay(RoundedRectangle(cornerRadius: 15).stroke(failedImage ? .gray : highlight_color(highlight), lineWidth: failedImage ? 1 : pfp_line_width(highlight)))
|
.overlay(RoundedRectangle(cornerRadius: 15).stroke(.gray.opacity(0.5), lineWidth: 0.5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ struct RelayStatusView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.trailing, 20)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,22 +10,31 @@ import SwiftUI
|
|||||||
struct RelayView: View {
|
struct RelayView: View {
|
||||||
let state: DamusState
|
let state: DamusState
|
||||||
let relay: String
|
let relay: String
|
||||||
|
let recommended: Bool
|
||||||
@ObservedObject private var model_cache: RelayModelCache
|
@ObservedObject private var model_cache: RelayModelCache
|
||||||
|
|
||||||
|
@State var relay_state: Bool
|
||||||
@Binding var showActionButtons: Bool
|
@Binding var showActionButtons: Bool
|
||||||
|
|
||||||
init(state: DamusState, relay: String, showActionButtons: Binding<Bool>) {
|
init(state: DamusState, relay: String, showActionButtons: Binding<Bool>, recommended: Bool) {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.relay = relay
|
self.relay = relay
|
||||||
|
self.recommended = recommended
|
||||||
self.model_cache = state.relay_model_cache
|
self.model_cache = state.relay_model_cache
|
||||||
_showActionButtons = showActionButtons
|
_showActionButtons = showActionButtons
|
||||||
|
let relay_state = RelayView.get_relay_state(pool: state.pool, relay: relay)
|
||||||
|
self._relay_state = State(initialValue: relay_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func get_relay_state(pool: RelayPool, relay: String) -> Bool {
|
||||||
|
return pool.get_relay(relay) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
HStack {
|
HStack {
|
||||||
if let privkey = state.keypair.privkey {
|
if let privkey = state.keypair.privkey {
|
||||||
if showActionButtons {
|
if showActionButtons && !recommended {
|
||||||
RemoveButton(privkey: privkey, showText: false)
|
RemoveButton(privkey: privkey, showText: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,33 +48,13 @@ struct RelayView: View {
|
|||||||
Text(meta?.name ?? relay)
|
Text(meta?.name ?? relay)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.padding(.bottom, 2)
|
.padding(.bottom, 2)
|
||||||
|
.lineLimit(1)
|
||||||
RelayType(is_paid: state.relay_model_cache.model(with_relay_id: relay)?.metadata.is_paid ?? false)
|
RelayType(is_paid: state.relay_model_cache.model(with_relay_id: relay)?.metadata.is_paid ?? false)
|
||||||
}
|
}
|
||||||
Text(relay)
|
Text(relay)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
.lineLimit(1)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let relay_connection {
|
|
||||||
RelayStatusView(connection: relay_connection)
|
|
||||||
.background(
|
|
||||||
NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta), label: {
|
|
||||||
EmptyView()
|
|
||||||
})
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.disabled(showActionButtons)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.swipeActions {
|
|
||||||
if let privkey = state.keypair.privkey {
|
|
||||||
RemoveButton(privkey: privkey, showText: false)
|
|
||||||
.tint(.red)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
CopyAction(relay: relay)
|
CopyAction(relay: relay)
|
||||||
|
|
||||||
@ -75,20 +64,68 @@ struct RelayView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if recommended {
|
||||||
|
if let keypair = state.keypair.to_full() {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
if relay_state {
|
||||||
|
AddButton(keypair: keypair)
|
||||||
|
} else {
|
||||||
|
Button(action: {
|
||||||
|
remove_action(privkey: keypair.privkey)
|
||||||
|
}) {
|
||||||
|
Text(NSLocalizedString("Added", comment: "Button to show relay server is already added to list."))
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
.buttonStyle(NeutralButtonShape.capsule.style)
|
||||||
|
.opacity(0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 5)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let relay_connection {
|
||||||
|
RelayStatusView(connection: relay_connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
Image("chevron-large-right")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 15, height: 15)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.relays_changed)) { _ in
|
||||||
|
self.relay_state = RelayView.get_relay_state(pool: state.pool, relay: self.relay)
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
state.nav.push(route: Route.RelayDetail(relay: relay, metadata: model_cache.model(with_relay_id: relay)?.metadata))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var relay_connection: RelayConnection? {
|
private var relay_connection: RelayConnection? {
|
||||||
state.pool.get_relay(relay)?.connection
|
state.pool.get_relay(relay)?.connection
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyAction(relay: String) -> some View {
|
func add_action(keypair: FullKeypair) {
|
||||||
Button {
|
guard let ev_before_add = state.contacts.event else {
|
||||||
UIPasteboard.general.setValue(relay, forPasteboardType: "public.plain-text")
|
return
|
||||||
} label: {
|
}
|
||||||
Label(NSLocalizedString("Copy", comment: "Button to copy a relay server address."), image: "copy2")
|
guard let relay_url = RelayURL(relay),
|
||||||
|
let ev_after_add = add_relay(ev: ev_before_add, keypair: keypair, current_relays: state.pool.our_descriptors, relay: relay_url, info: .rw) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process_contact_event(state: state, ev: ev_after_add)
|
||||||
|
state.postbox.send(ev_after_add)
|
||||||
|
|
||||||
|
if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) {
|
||||||
|
state.postbox.send(relay_metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveButton(privkey: Privkey, showText: Bool) -> some View {
|
func remove_action(privkey: Privkey) {
|
||||||
Button(action: {
|
|
||||||
guard let ev = state.contacts.event else {
|
guard let ev = state.contacts.event else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -106,6 +143,29 @@ struct RelayView: View {
|
|||||||
if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) {
|
if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) {
|
||||||
state.postbox.send(relay_metadata)
|
state.postbox.send(relay_metadata)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddButton(keypair: FullKeypair) -> some View {
|
||||||
|
Button(action: {
|
||||||
|
add_action(keypair: keypair)
|
||||||
|
}) {
|
||||||
|
Text(NSLocalizedString("Add", comment: "Button to add relay server to list."))
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
.buttonStyle(NeutralButtonShape.capsule.style)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyAction(relay: String) -> some View {
|
||||||
|
Button {
|
||||||
|
UIPasteboard.general.setValue(relay, forPasteboardType: "public.plain-text")
|
||||||
|
} label: {
|
||||||
|
Label(NSLocalizedString("Copy", comment: "Button to copy a relay server address."), image: "copy2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveButton(privkey: Privkey, showText: Bool) -> some View {
|
||||||
|
Button(action: {
|
||||||
|
remove_action(privkey: privkey)
|
||||||
}) {
|
}) {
|
||||||
if showText {
|
if showText {
|
||||||
Text(NSLocalizedString("Disconnect", comment: "Button to disconnect from a relay server."))
|
Text(NSLocalizedString("Disconnect", comment: "Button to disconnect from a relay server."))
|
||||||
@ -122,6 +182,6 @@ struct RelayView: View {
|
|||||||
|
|
||||||
struct RelayView_Previews: PreviewProvider {
|
struct RelayView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
RelayView(state: test_damus_state, relay: "wss://relay.damus.io", showActionButtons: .constant(false))
|
RelayView(state: test_damus_state, relay: "wss://relay.damus.io", showActionButtons: .constant(false), recommended: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
damus/Views/Reposts/QuoteRepostsView.swift
Normal file
31
damus/Views/Reposts/QuoteRepostsView.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// QuoteRepostsView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2024-03-16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct QuoteRepostsView: View {
|
||||||
|
let damus_state: DamusState
|
||||||
|
@ObservedObject var model: EventsModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
TimelineView<AnyView>(events: model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: ContentFilters.default_filters(damus_state: damus_state).filter(ev:))
|
||||||
|
.navigationBarTitle(NSLocalizedString("Quotes", comment: "Navigation bar title for Quote Reposts view."))
|
||||||
|
.onAppear {
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
model.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct QuoteRepostsView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
let state = test_damus_state
|
||||||
|
QuoteRepostsView(damus_state: state, model: .reposts(state: state, target: test_note.id))
|
||||||
|
}
|
||||||
|
}
|
@ -9,12 +9,12 @@ import SwiftUI
|
|||||||
|
|
||||||
struct RepostsView: View {
|
struct RepostsView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@StateObject var model: RepostsModel
|
@StateObject var model: EventsModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(model.events, id: \.id) { ev in
|
ForEach(model.events.events, id: \.id) { ev in
|
||||||
RepostView(damus_state: damus_state, repost: ev)
|
RepostView(damus_state: damus_state, repost: ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,6 +33,6 @@ struct RepostsView: View {
|
|||||||
struct RepostsView_Previews: PreviewProvider {
|
struct RepostsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let state = test_damus_state
|
let state = test_damus_state
|
||||||
RepostsView(damus_state: state, model: RepostsModel(state: state, target: test_note.id))
|
RepostsView(damus_state: state, model: .reposts(state: state, target: test_note.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,9 @@ struct UserRelaysView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List(relay_state, id: \.0) { (r, add) in
|
List(relay_state, id: \.0) { (r, add) in
|
||||||
RecommendedRelayView(damus: state, relay: r, add_button: add, user_recommended: true)
|
RelayView(state: state, relay: r, showActionButtons: .constant(true), recommended: true)
|
||||||
}
|
}
|
||||||
.listStyle(PlainListStyle())
|
.listStyle(PlainListStyle())
|
||||||
.onReceive(handle_notify(.relays_changed)) { _ in
|
|
||||||
self.relay_state = UserRelaysView.make_relay_state(pool: state.pool, relays: self.relays)
|
|
||||||
}
|
|
||||||
.navigationBarTitle(NSLocalizedString("Relays", comment: "Navigation bar title that shows the list of relays for a user."))
|
.navigationBarTitle(NSLocalizedString("Relays", comment: "Navigation bar title that shows the list of relays for a user."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,15 @@ struct ConnectWalletView: View {
|
|||||||
@ObservedObject var model: WalletModel
|
@ObservedObject var model: WalletModel
|
||||||
|
|
||||||
@State var scanning: Bool = false
|
@State var scanning: Bool = false
|
||||||
|
@State private var showAlert = false
|
||||||
@State var error: String? = nil
|
@State var error: String? = nil
|
||||||
@State var wallet_scan_result: WalletScanResult = .scanning
|
@State var wallet_scan_result: WalletScanResult = .scanning
|
||||||
var nav: NavigationCoordinator
|
var nav: NavigationCoordinator
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MainContent
|
MainContent
|
||||||
.navigationTitle(NSLocalizedString("Attach a Wallet", comment: "Navigation title for attaching Nostr Wallet Connect lightning wallet."))
|
.navigationTitle(NSLocalizedString("Wallet", comment: "Navigation title for attaching Nostr Wallet Connect lightning wallet."))
|
||||||
.navigationBarTitleDisplayMode(.large)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.padding()
|
.padding()
|
||||||
.onChange(of: wallet_scan_result) { res in
|
.onChange(of: wallet_scan_result) { res in
|
||||||
scanning = false
|
scanning = false
|
||||||
@ -30,18 +31,29 @@ struct ConnectWalletView: View {
|
|||||||
self.model.new(url)
|
self.model.new(url)
|
||||||
|
|
||||||
case .failed:
|
case .failed:
|
||||||
error = NSLocalizedString("Invalid Nostr wallet connection string", comment: "Error message when an invalid Nostr wallet connection string is provided.")
|
showAlert.toggle()
|
||||||
|
|
||||||
case .scanning:
|
case .scanning:
|
||||||
error = nil
|
error = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert(isPresented: $showAlert) {
|
||||||
|
Alert(
|
||||||
|
title: Text(NSLocalizedString("Invalid Nostr wallet connection string", comment: "Error message when an invalid Nostr wallet connection string is provided.")),
|
||||||
|
message: Text("Make sure the wallet you are connecting to supports NWC."),
|
||||||
|
dismissButton: .default(Text(NSLocalizedString("OK", comment: "Button label indicating user wants to proceed."))) {
|
||||||
|
wallet_scan_result = .scanning
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AreYouSure(nwc: WalletConnectURL) -> some View {
|
func AreYouSure(nwc: WalletConnectURL) -> some View {
|
||||||
VStack {
|
VStack(spacing: 25) {
|
||||||
Text("Are you sure you want to attach this wallet?", comment: "Prompt to ask user if they want to attach their Nostr Wallet Connect lightning wallet.")
|
|
||||||
.font(.title)
|
Text("Are you sure you want to connect this wallet?", comment: "Prompt to ask user if they want to attach their Nostr Wallet Connect lightning wallet.")
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
Text(nwc.relay.id)
|
Text(nwc.relay.id)
|
||||||
.font(.body)
|
.font(.body)
|
||||||
@ -53,26 +65,73 @@ struct ConnectWalletView: View {
|
|||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
|
|
||||||
BigButton(NSLocalizedString("Attach", comment: "Text for button to attach Nostr Wallet Connect lightning wallet.")) {
|
Button(action: {
|
||||||
model.connect(nwc)
|
model.connect(nwc)
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Text("Connect", comment: "Text for button to conect to Nostr Wallet Connect lightning wallet.")
|
||||||
|
.fontWeight(.semibold)
|
||||||
}
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, maxHeight: 18, alignment: .center)
|
||||||
|
}
|
||||||
|
.buttonStyle(GradientButtonStyle())
|
||||||
|
|
||||||
BigButton(NSLocalizedString("Cancel", comment: "Text for button to cancel out of connecting Nostr Wallet Connect lightning ewallet.")) {
|
Button(action: {
|
||||||
model.cancel()
|
model.cancel()
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Text(NSLocalizedString("Cancel", comment: "Text for button to cancel out of connecting Nostr Wallet Connect lightning wallet."))
|
||||||
|
.padding()
|
||||||
}
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, alignment: .center)
|
||||||
|
}
|
||||||
|
.buttonStyle(NeutralButtonStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConnectWallet: some View {
|
var ConnectWallet: some View {
|
||||||
VStack {
|
VStack(spacing: 25) {
|
||||||
|
|
||||||
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.")) {
|
MutinyButton() {
|
||||||
nav.push(route: Route.WalletScanner(result: $wallet_scan_result))
|
openURL(URL(string:"https://app.mutinywallet.com/settings/connections")!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button(action: {
|
||||||
|
if let pasted_nwc = UIPasteboard.general.string {
|
||||||
|
guard let url = WalletConnectURL(str: pasted_nwc) else {
|
||||||
|
wallet_scan_result = .failed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet_scan_result = .success(url)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image("clipboard")
|
||||||
|
Text("Paste NWC Address", comment: "Text for button to connect a lightning wallet.")
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, maxHeight: 18, alignment: .center)
|
||||||
|
}
|
||||||
|
.buttonStyle(GradientButtonStyle())
|
||||||
|
|
||||||
|
Button(action: {
|
||||||
|
nav.push(route: Route.WalletScanner(result: $wallet_scan_result))
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Image("qr-code")
|
||||||
|
Text("Scan NWC Address", comment: "Text for button to connect a lightning wallet.")
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, maxHeight: 18, alignment: .center)
|
||||||
|
}
|
||||||
|
.buttonStyle(GradientButtonStyle())
|
||||||
|
|
||||||
|
|
||||||
if let err = self.error {
|
if let err = self.error {
|
||||||
Text(err)
|
Text(err)
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
@ -80,14 +139,54 @@ struct ConnectWalletView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var TopSection: some View {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Button(action: {}, label: {
|
||||||
|
Image("damus-home")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
})
|
||||||
|
.buttonStyle(NeutralButtonStyle(padding: EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15), cornerRadius: 9999))
|
||||||
|
.disabled(true)
|
||||||
|
.padding(.horizontal, 30)
|
||||||
|
|
||||||
|
Image("chevron-double-right")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 25, height: 25)
|
||||||
|
|
||||||
|
Button(action: {}, label: {
|
||||||
|
Image("wallet")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
.foregroundStyle(LINEAR_GRADIENT)
|
||||||
|
})
|
||||||
|
.buttonStyle(NeutralButtonStyle(padding: EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15), cornerRadius: 9999))
|
||||||
|
.disabled(true)
|
||||||
|
.padding(.horizontal, 30)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var TitleSection: some View {
|
||||||
|
VStack(spacing: 25) {
|
||||||
|
Text("Damus Wallet")
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Text("Securely connect your Damus app to your wallet\nusing Nostr Wallet Connect")
|
||||||
|
.font(.caption)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
Group {
|
Group {
|
||||||
|
TopSection
|
||||||
switch model.connect_state {
|
switch model.connect_state {
|
||||||
case .new(let nwc):
|
case .new(let nwc):
|
||||||
AreYouSure(nwc: nwc)
|
AreYouSure(nwc: nwc)
|
||||||
case .existing:
|
case .existing:
|
||||||
Text(verbatim: "Shouldn't happen")
|
Text(verbatim: "Shouldn't happen")
|
||||||
case .none:
|
case .none:
|
||||||
|
TitleSection
|
||||||
ConnectWallet
|
ConnectWallet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,41 +45,6 @@ enum WalletScanResult: Equatable {
|
|||||||
case scanning
|
case scanning
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NWCPaste: View {
|
|
||||||
@Binding var result: WalletScanResult
|
|
||||||
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
|
||||||
|
|
||||||
init(result: Binding<WalletScanResult>) {
|
|
||||||
self._result = result
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button(action: {
|
|
||||||
if let pasted_nwc = UIPasteboard.general.string {
|
|
||||||
guard let url = WalletConnectURL(str: pasted_nwc) else {
|
|
||||||
self.result = .failed
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.result = .success(url)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "doc.on.clipboard")
|
|
||||||
Text("Paste", comment: "Button to paste a Nostr Wallet Connect string to connect the wallet for use in Damus for zaps.")
|
|
||||||
}
|
|
||||||
.frame(minWidth: 300, maxWidth: .infinity, minHeight: 50, maxHeight: 50, alignment: .center)
|
|
||||||
.foregroundColor(colorScheme == .light ? DamusColors.black : DamusColors.white)
|
|
||||||
.overlay {
|
|
||||||
RoundedRectangle(cornerRadius: 24)
|
|
||||||
.stroke(colorScheme == .light ? DamusColors.black : DamusColors.white, lineWidth: 2)
|
|
||||||
}
|
|
||||||
.padding(EdgeInsets(top: 10, leading: 50, bottom: 25, trailing: 50))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WalletScannerView: View {
|
struct WalletScannerView: View {
|
||||||
@Binding var result: WalletScanResult
|
@Binding var result: WalletScanResult
|
||||||
|
|
||||||
@ -92,6 +57,7 @@ struct WalletScannerView: View {
|
|||||||
case .success(let success):
|
case .success(let success):
|
||||||
guard let url = WalletConnectURL(str: success.string) else {
|
guard let url = WalletConnectURL(str: success.string) else {
|
||||||
result = .failed
|
result = .failed
|
||||||
|
dismiss()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +68,6 @@ struct WalletScannerView: View {
|
|||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
NWCPaste(result: $result)
|
|
||||||
.padding(.vertical)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,19 +26,58 @@ struct WalletView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(verbatim: nwc.relay.id)
|
VStack(spacing: 5) {
|
||||||
|
VStack(spacing: 10) {
|
||||||
|
Text("Wallet Relay")
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.top)
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
RelayView(state: damus_state, relay: nwc.relay.id, showActionButtons: .constant(false), recommended: false)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, minHeight: 125, alignment: .top)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
.background(DamusColors.neutral1)
|
||||||
|
.cornerRadius(10)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.stroke(DamusColors.neutral3, lineWidth: 1)
|
||||||
|
)
|
||||||
|
|
||||||
if let lud16 = nwc.lud16 {
|
if let lud16 = nwc.lud16 {
|
||||||
|
VStack(spacing: 10) {
|
||||||
|
Text("Wallet Address")
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
Text(verbatim: lud16)
|
Text(verbatim: lud16)
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: .infinity, minHeight: 75, alignment: .center)
|
||||||
BigButton(NSLocalizedString("Disconnect Wallet", comment: "Text for button to disconnect from Nostr Wallet Connect lightning wallet.")) {
|
.padding(.horizontal, 10)
|
||||||
self.model.disconnect()
|
.background(DamusColors.neutral1)
|
||||||
|
.cornerRadius(10)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.stroke(DamusColors.neutral3, lineWidth: 1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(action: {
|
||||||
|
self.model.disconnect()
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Text(NSLocalizedString("Disconnect Wallet", comment: "Text for button to disconnect from Nostr Wallet Connect lightning wallet."))
|
||||||
|
}
|
||||||
|
.frame(minWidth: 300, maxWidth: .infinity, maxHeight: 18, alignment: .center)
|
||||||
|
}
|
||||||
|
.buttonStyle(GradientButtonStyle())
|
||||||
|
|
||||||
}
|
}
|
||||||
.navigationTitle(NSLocalizedString("Wallet", comment: "Navigation title for Wallet view"))
|
.navigationTitle(NSLocalizedString("Wallet", comment: "Navigation title for Wallet view"))
|
||||||
.navigationBarTitleDisplayMode(.large)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +226,22 @@
|
|||||||
<string>Reposts</string>
|
<string>Reposts</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>quoted_reposts_count</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@QUOTE_REPOSTS@</string>
|
||||||
|
<key>QUOTE_REPOSTS</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>d</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>Quote</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>Quotes</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>sats</key>
|
<key>sats</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSStringLocalizedFormatKey</key>
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
@ -49,7 +49,8 @@ func generate_test_damus_state(
|
|||||||
nav: .init(),
|
nav: .init(),
|
||||||
music: .init(onChange: {_ in }),
|
music: .init(onChange: {_ in }),
|
||||||
video: .init(),
|
video: .init(),
|
||||||
ndb: ndb)
|
ndb: ndb,
|
||||||
|
quote_reposts: .init(our_pubkey: our_pubkey) )
|
||||||
|
|
||||||
return damus
|
return damus
|
||||||
}
|
}
|
||||||
|
@ -280,6 +280,13 @@ extension NdbNote {
|
|||||||
return kind == 1 || kind == 42 || kind == 30023
|
return kind == 1 || kind == 42 || kind == 30023
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var is_quote_repost: NoteId? {
|
||||||
|
guard kind == 1, let quoted_note_id = referenced_quote_ids.first else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return quoted_note_id.note_id
|
||||||
|
}
|
||||||
|
|
||||||
var known_kind: NostrKind? {
|
var known_kind: NostrKind? {
|
||||||
return NostrKind.init(rawValue: kind)
|
return NostrKind.init(rawValue: kind)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user