Damus Live
This PR adds Live Streaming and Live Chat to Damus via Damus Labs. Changelog-Added: Added live stream timeline Changelog-Added: Added live chat timeline Changelog-Added: Added ability to create live chat event Changelog-Added: Damus Labs Toggle Signed-off-by: ericholguin <ericholguin@apache.org>
This commit is contained in:
committed by
Daniel D’Aquino
parent
a31f6bce0e
commit
b8c664d354
@@ -531,6 +531,60 @@
|
|||||||
5C8498032D5D150000F74FEB /* ZapExplainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */; };
|
5C8498032D5D150000F74FEB /* ZapExplainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */; };
|
||||||
5C8498042D5D150000F74FEB /* ZapExplainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */; };
|
5C8498042D5D150000F74FEB /* ZapExplainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */; };
|
||||||
5C8711DE2C460C06007879C2 /* PostingTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8711DD2C460C06007879C2 /* PostingTimelineView.swift */; };
|
5C8711DE2C460C06007879C2 /* PostingTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8711DD2C460C06007879C2 /* PostingTimelineView.swift */; };
|
||||||
|
5C8F970A2EB45E8C009399B1 /* LiveChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97092EB45E85009399B1 /* LiveChatModel.swift */; };
|
||||||
|
5C8F970B2EB45E8C009399B1 /* LiveChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97092EB45E85009399B1 /* LiveChatModel.swift */; };
|
||||||
|
5C8F970C2EB45E8C009399B1 /* LiveChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97092EB45E85009399B1 /* LiveChatModel.swift */; };
|
||||||
|
5C8F970E2EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F970D2EB45F68009399B1 /* LiveChatHomeView.swift */; };
|
||||||
|
5C8F970F2EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F970D2EB45F68009399B1 /* LiveChatHomeView.swift */; };
|
||||||
|
5C8F97102EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F970D2EB45F68009399B1 /* LiveChatHomeView.swift */; };
|
||||||
|
5C8F97122EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97112EB45FA3009399B1 /* LiveChatTimeline.swift */; };
|
||||||
|
5C8F97132EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97112EB45FA3009399B1 /* LiveChatTimeline.swift */; };
|
||||||
|
5C8F97142EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97112EB45FA3009399B1 /* LiveChatTimeline.swift */; };
|
||||||
|
5C8F97162EB45FD7009399B1 /* LiveChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97152EB45FD1009399B1 /* LiveChatView.swift */; };
|
||||||
|
5C8F97172EB45FD7009399B1 /* LiveChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97152EB45FD1009399B1 /* LiveChatView.swift */; };
|
||||||
|
5C8F97182EB45FD7009399B1 /* LiveChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97152EB45FD1009399B1 /* LiveChatView.swift */; };
|
||||||
|
5C8F971C2EB4607B009399B1 /* LiveEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971B2EB46078009399B1 /* LiveEvent.swift */; };
|
||||||
|
5C8F971D2EB4607B009399B1 /* LiveEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971B2EB46078009399B1 /* LiveEvent.swift */; };
|
||||||
|
5C8F971E2EB4607B009399B1 /* LiveEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971B2EB46078009399B1 /* LiveEvent.swift */; };
|
||||||
|
5C8F97202EB46097009399B1 /* LiveEventModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971F2EB46093009399B1 /* LiveEventModel.swift */; };
|
||||||
|
5C8F97212EB46097009399B1 /* LiveEventModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971F2EB46093009399B1 /* LiveEventModel.swift */; };
|
||||||
|
5C8F97222EB46097009399B1 /* LiveEventModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F971F2EB46093009399B1 /* LiveEventModel.swift */; };
|
||||||
|
5C8F97252EB460CA009399B1 /* LiveStreamBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97242EB460C2009399B1 /* LiveStreamBanner.swift */; };
|
||||||
|
5C8F97262EB460CA009399B1 /* LiveStreamBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97242EB460C2009399B1 /* LiveStreamBanner.swift */; };
|
||||||
|
5C8F97272EB460CA009399B1 /* LiveStreamBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97242EB460C2009399B1 /* LiveStreamBanner.swift */; };
|
||||||
|
5C8F97292EB460E6009399B1 /* LiveStreamProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97282EB460DC009399B1 /* LiveStreamProfile.swift */; };
|
||||||
|
5C8F972A2EB460E6009399B1 /* LiveStreamProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97282EB460DC009399B1 /* LiveStreamProfile.swift */; };
|
||||||
|
5C8F972B2EB460E6009399B1 /* LiveStreamProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97282EB460DC009399B1 /* LiveStreamProfile.swift */; };
|
||||||
|
5C8F972D2EB46116009399B1 /* LiveStreamStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F972C2EB4610F009399B1 /* LiveStreamStatus.swift */; };
|
||||||
|
5C8F972E2EB46116009399B1 /* LiveStreamStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F972C2EB4610F009399B1 /* LiveStreamStatus.swift */; };
|
||||||
|
5C8F972F2EB46116009399B1 /* LiveStreamStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F972C2EB4610F009399B1 /* LiveStreamStatus.swift */; };
|
||||||
|
5C8F97312EB46126009399B1 /* LiveStreamViewers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97302EB46121009399B1 /* LiveStreamViewers.swift */; };
|
||||||
|
5C8F97322EB46126009399B1 /* LiveStreamViewers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97302EB46121009399B1 /* LiveStreamViewers.swift */; };
|
||||||
|
5C8F97332EB46126009399B1 /* LiveStreamViewers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97302EB46121009399B1 /* LiveStreamViewers.swift */; };
|
||||||
|
5C8F97352EB46145009399B1 /* LiveStreamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97342EB46141009399B1 /* LiveStreamView.swift */; };
|
||||||
|
5C8F97362EB46145009399B1 /* LiveStreamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97342EB46141009399B1 /* LiveStreamView.swift */; };
|
||||||
|
5C8F97372EB46145009399B1 /* LiveStreamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97342EB46141009399B1 /* LiveStreamView.swift */; };
|
||||||
|
5C8F97392EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97382EB46167009399B1 /* LiveStreamTimeline.swift */; };
|
||||||
|
5C8F973A2EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97382EB46167009399B1 /* LiveStreamTimeline.swift */; };
|
||||||
|
5C8F973B2EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97382EB46167009399B1 /* LiveStreamTimeline.swift */; };
|
||||||
|
5C8F973D2EB46197009399B1 /* LiveStreamPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F973C2EB46192009399B1 /* LiveStreamPreview.swift */; };
|
||||||
|
5C8F973E2EB46197009399B1 /* LiveStreamPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F973C2EB46192009399B1 /* LiveStreamPreview.swift */; };
|
||||||
|
5C8F973F2EB46197009399B1 /* LiveStreamPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F973C2EB46192009399B1 /* LiveStreamPreview.swift */; };
|
||||||
|
5C8F97412EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97402EB461AB009399B1 /* LiveStreamHomeView.swift */; };
|
||||||
|
5C8F97422EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97402EB461AB009399B1 /* LiveStreamHomeView.swift */; };
|
||||||
|
5C8F97432EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97402EB461AB009399B1 /* LiveStreamHomeView.swift */; };
|
||||||
|
5C8F97452EB461DB009399B1 /* EventTags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97442EB461D6009399B1 /* EventTags.swift */; };
|
||||||
|
5C8F97462EB461DB009399B1 /* EventTags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97442EB461D6009399B1 /* EventTags.swift */; };
|
||||||
|
5C8F97472EB461DB009399B1 /* EventTags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97442EB461D6009399B1 /* EventTags.swift */; };
|
||||||
|
5C8F97492EB4620A009399B1 /* Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97482EB46208009399B1 /* Glow.swift */; };
|
||||||
|
5C8F974A2EB4620A009399B1 /* Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97482EB46208009399B1 /* Glow.swift */; };
|
||||||
|
5C8F974B2EB4620A009399B1 /* Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97482EB46208009399B1 /* Glow.swift */; };
|
||||||
|
5C8F974E2EBD704A009399B1 /* LabsToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F974D2EBD7044009399B1 /* LabsToggleView.swift */; };
|
||||||
|
5C8F974F2EBD704A009399B1 /* LabsToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F974D2EBD7044009399B1 /* LabsToggleView.swift */; };
|
||||||
|
5C8F97502EBD704A009399B1 /* LabsToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F974D2EBD7044009399B1 /* LabsToggleView.swift */; };
|
||||||
|
5C8F97522EBD7083009399B1 /* LabsExplainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97512EBD7071009399B1 /* LabsExplainerView.swift */; };
|
||||||
|
5C8F97532EBD7083009399B1 /* LabsExplainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97512EBD7071009399B1 /* LabsExplainerView.swift */; };
|
||||||
|
5C8F97542EBD7083009399B1 /* LabsExplainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8F97512EBD7071009399B1 /* LabsExplainerView.swift */; };
|
||||||
5CB017212D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
5CB017212D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
||||||
5CB017222D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
5CB017222D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
||||||
5CB017232D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
5CB017232D2D985E00A9ED05 /* CoinosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017202D2D985800A9ED05 /* CoinosButton.swift */; };
|
||||||
@@ -552,9 +606,9 @@
|
|||||||
5CB645A12EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
5CB645A12EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
||||||
5CB645A22EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
5CB645A22EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
||||||
5CB645A32EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
5CB645A32EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
|
||||||
5CB645A92EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
|
5CB645A92EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExperiments.swift */; };
|
||||||
5CB645AA2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
|
5CB645AA2EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExperiments.swift */; };
|
||||||
5CB645AB2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
|
5CB645AB2EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExperiments.swift */; };
|
||||||
5CC8529D2BD741CD0039FFC5 /* HighlightEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */; };
|
5CC8529D2BD741CD0039FFC5 /* HighlightEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */; };
|
||||||
5CC8529F2BD744F60039FFC5 /* HighlightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529E2BD744F60039FFC5 /* HighlightView.swift */; };
|
5CC8529F2BD744F60039FFC5 /* HighlightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529E2BD744F60039FFC5 /* HighlightView.swift */; };
|
||||||
5CC852A22BDED9B90039FFC5 /* HighlightDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */; };
|
5CC852A22BDED9B90039FFC5 /* HighlightDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */; };
|
||||||
@@ -2574,6 +2628,24 @@
|
|||||||
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>"; };
|
||||||
5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZapExplainer.swift; sourceTree = "<group>"; };
|
5C8498012D5D14FA00F74FEB /* ZapExplainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZapExplainer.swift; sourceTree = "<group>"; };
|
||||||
5C8711DD2C460C06007879C2 /* PostingTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostingTimelineView.swift; sourceTree = "<group>"; };
|
5C8711DD2C460C06007879C2 /* PostingTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostingTimelineView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97092EB45E85009399B1 /* LiveChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveChatModel.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F970D2EB45F68009399B1 /* LiveChatHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveChatHomeView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97112EB45FA3009399B1 /* LiveChatTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveChatTimeline.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97152EB45FD1009399B1 /* LiveChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveChatView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F971B2EB46078009399B1 /* LiveEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveEvent.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F971F2EB46093009399B1 /* LiveEventModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveEventModel.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97242EB460C2009399B1 /* LiveStreamBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamBanner.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97282EB460DC009399B1 /* LiveStreamProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamProfile.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F972C2EB4610F009399B1 /* LiveStreamStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamStatus.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97302EB46121009399B1 /* LiveStreamViewers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamViewers.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97342EB46141009399B1 /* LiveStreamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97382EB46167009399B1 /* LiveStreamTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamTimeline.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F973C2EB46192009399B1 /* LiveStreamPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamPreview.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97402EB461AB009399B1 /* LiveStreamHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamHomeView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97442EB461D6009399B1 /* EventTags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventTags.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97482EB46208009399B1 /* Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glow.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F974D2EBD7044009399B1 /* LabsToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsToggleView.swift; sourceTree = "<group>"; };
|
||||||
|
5C8F97512EBD7071009399B1 /* LabsExplainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsExplainerView.swift; sourceTree = "<group>"; };
|
||||||
5CB017202D2D985800A9ED05 /* CoinosButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinosButton.swift; sourceTree = "<group>"; };
|
5CB017202D2D985800A9ED05 /* CoinosButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinosButton.swift; sourceTree = "<group>"; };
|
||||||
5CB017242D42C5BD00A9ED05 /* TransactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsView.swift; sourceTree = "<group>"; };
|
5CB017242D42C5BD00A9ED05 /* TransactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsView.swift; sourceTree = "<group>"; };
|
||||||
5CB0172C2D42C76600A9ED05 /* BalanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceView.swift; sourceTree = "<group>"; };
|
5CB0172C2D42C76600A9ED05 /* BalanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceView.swift; sourceTree = "<group>"; };
|
||||||
@@ -2581,7 +2653,7 @@
|
|||||||
5CB645972EA317CC0018BD91 /* DamusLabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabs.swift; sourceTree = "<group>"; };
|
5CB645972EA317CC0018BD91 /* DamusLabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabs.swift; sourceTree = "<group>"; };
|
||||||
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsIntroduction.swift; sourceTree = "<group>"; };
|
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsIntroduction.swift; sourceTree = "<group>"; };
|
||||||
5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsLogoView.swift; sourceTree = "<group>"; };
|
5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsLogoView.swift; sourceTree = "<group>"; };
|
||||||
5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabsExpirements.swift; sourceTree = "<group>"; };
|
5CB645A82EAC013A0018BD91 /* DamusLabsExperiments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabsExperiments.swift; sourceTree = "<group>"; };
|
||||||
5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightEvent.swift; sourceTree = "<group>"; };
|
5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightEvent.swift; sourceTree = "<group>"; };
|
||||||
5CC8529E2BD744F60039FFC5 /* HighlightView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightView.swift; sourceTree = "<group>"; };
|
5CC8529E2BD744F60039FFC5 /* HighlightView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightView.swift; sourceTree = "<group>"; };
|
||||||
5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightDescription.swift; sourceTree = "<group>"; };
|
5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightDescription.swift; sourceTree = "<group>"; };
|
||||||
@@ -3663,6 +3735,7 @@
|
|||||||
5C513FCB2984ACA60072348F /* QRCodeView.swift */,
|
5C513FCB2984ACA60072348F /* QRCodeView.swift */,
|
||||||
4C363A8B28236B92006E126D /* PubkeyView.swift */,
|
4C363A8B28236B92006E126D /* PubkeyView.swift */,
|
||||||
4C8D00CB29DF92DF0036AF10 /* Hashtags.swift */,
|
4C8D00CB29DF92DF0036AF10 /* Hashtags.swift */,
|
||||||
|
5C8F97442EB461D6009399B1 /* EventTags.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -4049,6 +4122,7 @@
|
|||||||
5C78A7792E22FDFE00CF177D /* Features */ = {
|
5C78A7792E22FDFE00CF177D /* Features */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
5C8F97042EB45E39009399B1 /* Live */,
|
||||||
D5C1AFC22E5DFF040092F72F /* ContactCard */,
|
D5C1AFC22E5DFF040092F72F /* ContactCard */,
|
||||||
5C78A7BC2E304D7400CF177D /* Translations */,
|
5C78A7BC2E304D7400CF177D /* Translations */,
|
||||||
5C78A7B52E3046F400CF177D /* NIP05 */,
|
5C78A7B52E3046F400CF177D /* NIP05 */,
|
||||||
@@ -4884,12 +4958,100 @@
|
|||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
5C8F97042EB45E39009399B1 /* Live */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97062EB45E53009399B1 /* LiveStream */,
|
||||||
|
5C8F97052EB45E4C009399B1 /* LiveChat */,
|
||||||
|
);
|
||||||
|
path = Live;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97052EB45E4C009399B1 /* LiveChat */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97072EB45E5F009399B1 /* Models */,
|
||||||
|
5C8F97082EB45E63009399B1 /* Views */,
|
||||||
|
);
|
||||||
|
path = LiveChat;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97062EB45E53009399B1 /* LiveStream */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F971A2EB4600C009399B1 /* Views */,
|
||||||
|
5C8F97192EB46005009399B1 /* Models */,
|
||||||
|
);
|
||||||
|
path = LiveStream;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97072EB45E5F009399B1 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97092EB45E85009399B1 /* LiveChatModel.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97082EB45E63009399B1 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97152EB45FD1009399B1 /* LiveChatView.swift */,
|
||||||
|
5C8F97112EB45FA3009399B1 /* LiveChatTimeline.swift */,
|
||||||
|
5C8F970D2EB45F68009399B1 /* LiveChatHomeView.swift */,
|
||||||
|
);
|
||||||
|
path = Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97192EB46005009399B1 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F971F2EB46093009399B1 /* LiveEventModel.swift */,
|
||||||
|
5C8F971B2EB46078009399B1 /* LiveEvent.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F971A2EB4600C009399B1 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97402EB461AB009399B1 /* LiveStreamHomeView.swift */,
|
||||||
|
5C8F973C2EB46192009399B1 /* LiveStreamPreview.swift */,
|
||||||
|
5C8F97382EB46167009399B1 /* LiveStreamTimeline.swift */,
|
||||||
|
5C8F97342EB46141009399B1 /* LiveStreamView.swift */,
|
||||||
|
5C8F97232EB460B8009399B1 /* Components */,
|
||||||
|
);
|
||||||
|
path = Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F97232EB460B8009399B1 /* Components */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97302EB46121009399B1 /* LiveStreamViewers.swift */,
|
||||||
|
5C8F972C2EB4610F009399B1 /* LiveStreamStatus.swift */,
|
||||||
|
5C8F97282EB460DC009399B1 /* LiveStreamProfile.swift */,
|
||||||
|
5C8F97242EB460C2009399B1 /* LiveStreamBanner.swift */,
|
||||||
|
);
|
||||||
|
path = Components;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
5C8F974C2EBD703D009399B1 /* Components */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C8F97512EBD7071009399B1 /* LabsExplainerView.swift */,
|
||||||
|
5C8F974D2EBD7044009399B1 /* LabsToggleView.swift */,
|
||||||
|
);
|
||||||
|
path = Components;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
5CB645952EA3106A0018BD91 /* Views */ = {
|
5CB645952EA3106A0018BD91 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */,
|
5C8F974C2EBD703D009399B1 /* Components */,
|
||||||
|
5CB645A82EAC013A0018BD91 /* DamusLabsExperiments.swift */,
|
||||||
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */,
|
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */,
|
||||||
5CB645972EA317CC0018BD91 /* DamusLabs.swift */,
|
5CB645972EA317CC0018BD91 /* DamusLabs.swift */,
|
||||||
|
5CB6459F2EA31E2C0018BD91 /* Detail */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -4897,7 +5059,6 @@
|
|||||||
5CB645962EA3106A0018BD91 /* Labs */ = {
|
5CB645962EA3106A0018BD91 /* Labs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5CB6459F2EA31E2C0018BD91 /* Detail */,
|
|
||||||
5CB645952EA3106A0018BD91 /* Views */,
|
5CB645952EA3106A0018BD91 /* Views */,
|
||||||
);
|
);
|
||||||
path = Labs;
|
path = Labs;
|
||||||
@@ -5144,6 +5305,7 @@
|
|||||||
F7F0BA23297892AE009531F3 /* Modifiers */ = {
|
F7F0BA23297892AE009531F3 /* Modifiers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
5C8F97482EB46208009399B1 /* Glow.swift */,
|
||||||
F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */,
|
F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */,
|
||||||
);
|
);
|
||||||
path = Modifiers;
|
path = Modifiers;
|
||||||
@@ -5519,9 +5681,11 @@
|
|||||||
4C3DCC762A9FE9EC0091E592 /* NdbTxn.swift in Sources */,
|
4C3DCC762A9FE9EC0091E592 /* NdbTxn.swift in Sources */,
|
||||||
4CEF958D2A9CE650000F901B /* verifier.c in Sources */,
|
4CEF958D2A9CE650000F901B /* verifier.c in Sources */,
|
||||||
D73BDB0E2D6FF5F600D69970 /* NostrNetworkManager.swift in Sources */,
|
D73BDB0E2D6FF5F600D69970 /* NostrNetworkManager.swift in Sources */,
|
||||||
|
5C8F97262EB460CA009399B1 /* LiveStreamBanner.swift in Sources */,
|
||||||
4C32B9332A99845B00DC3548 /* Ndb.swift in Sources */,
|
4C32B9332A99845B00DC3548 /* Ndb.swift in Sources */,
|
||||||
D7ADD3E22B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift in Sources */,
|
D7ADD3E22B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift in Sources */,
|
||||||
4C4793082A993E8900489948 /* refmap.c in Sources */,
|
4C4793082A993E8900489948 /* refmap.c in Sources */,
|
||||||
|
5C8F972D2EB46116009399B1 /* LiveStreamStatus.swift in Sources */,
|
||||||
4C4793072A993E6200489948 /* emitter.c in Sources */,
|
4C4793072A993E6200489948 /* emitter.c in Sources */,
|
||||||
4C4793062A993E5300489948 /* json_parser.c in Sources */,
|
4C4793062A993E5300489948 /* json_parser.c in Sources */,
|
||||||
4C4793052A993E3200489948 /* builder.c in Sources */,
|
4C4793052A993E3200489948 /* builder.c in Sources */,
|
||||||
@@ -5539,6 +5703,7 @@
|
|||||||
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
|
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
|
||||||
4CDD1AE22A6B3074001CD4DF /* NdbTagsIterator.swift in Sources */,
|
4CDD1AE22A6B3074001CD4DF /* NdbTagsIterator.swift in Sources */,
|
||||||
4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
|
4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
|
||||||
|
5C8F97522EBD7083009399B1 /* LabsExplainerView.swift in Sources */,
|
||||||
D7CB5D512B1174D100AD4105 /* FriendFilter.swift in Sources */,
|
D7CB5D512B1174D100AD4105 /* FriendFilter.swift in Sources */,
|
||||||
D74DEC8C2DA0A19B00E69FA6 /* Ndb+.swift in Sources */,
|
D74DEC8C2DA0A19B00E69FA6 /* Ndb+.swift in Sources */,
|
||||||
D7CBD1D42B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift in Sources */,
|
D7CBD1D42B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift in Sources */,
|
||||||
@@ -5558,6 +5723,7 @@
|
|||||||
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
|
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
|
||||||
4CDA128A29E9D10C0006FA5A /* SignalView.swift in Sources */,
|
4CDA128A29E9D10C0006FA5A /* SignalView.swift in Sources */,
|
||||||
4C12535C2A76CA540004F4B8 /* LoginNotify.swift in Sources */,
|
4C12535C2A76CA540004F4B8 /* LoginNotify.swift in Sources */,
|
||||||
|
5C8F97222EB46097009399B1 /* LiveEventModel.swift in Sources */,
|
||||||
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */,
|
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */,
|
||||||
4C54AA0C29A5543C003E4487 /* ZapGroup.swift in Sources */,
|
4C54AA0C29A5543C003E4487 /* ZapGroup.swift in Sources */,
|
||||||
4C190F202A535FC200027FD5 /* CustomizeZapModel.swift in Sources */,
|
4C190F202A535FC200027FD5 /* CustomizeZapModel.swift in Sources */,
|
||||||
@@ -5636,6 +5802,7 @@
|
|||||||
4CF0ABE32981BC7D00D66079 /* UserView.swift in Sources */,
|
4CF0ABE32981BC7D00D66079 /* UserView.swift in Sources */,
|
||||||
4CE0E2AF29A2E82100DB4CA2 /* EventHolder.swift in Sources */,
|
4CE0E2AF29A2E82100DB4CA2 /* EventHolder.swift in Sources */,
|
||||||
B51C1CEA2B55A60A00E312A9 /* AddMuteItemView.swift in Sources */,
|
B51C1CEA2B55A60A00E312A9 /* AddMuteItemView.swift in Sources */,
|
||||||
|
5C8F97332EB46126009399B1 /* LiveStreamViewers.swift in Sources */,
|
||||||
4C5D5C992A6AF8F80024563C /* NdbNote.swift in Sources */,
|
4C5D5C992A6AF8F80024563C /* NdbNote.swift in Sources */,
|
||||||
4CF0ABF029857E9200D66079 /* Bech32Object.swift in Sources */,
|
4CF0ABF029857E9200D66079 /* Bech32Object.swift in Sources */,
|
||||||
D7D68FFA2C9E01BE0015A515 /* KFClickable.swift in Sources */,
|
D7D68FFA2C9E01BE0015A515 /* KFClickable.swift in Sources */,
|
||||||
@@ -5663,6 +5830,7 @@
|
|||||||
D5C1AFC62E5DFF700092F72F /* ContactCardManagerMock.swift in Sources */,
|
D5C1AFC62E5DFF700092F72F /* ContactCardManagerMock.swift in Sources */,
|
||||||
4C4DD3DB2A6CA7E8005B4E85 /* ContentParsing.swift in Sources */,
|
4C4DD3DB2A6CA7E8005B4E85 /* ContentParsing.swift in Sources */,
|
||||||
F71694F22A67314D001F4053 /* SuggestedUserView.swift in Sources */,
|
F71694F22A67314D001F4053 /* SuggestedUserView.swift in Sources */,
|
||||||
|
5C8F97172EB45FD7009399B1 /* LiveChatView.swift in Sources */,
|
||||||
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */,
|
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */,
|
||||||
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
|
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
|
||||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
||||||
@@ -5755,6 +5923,7 @@
|
|||||||
7C95CAEE299DCEF1009DCB67 /* KFOptionSetter+.swift in Sources */,
|
7C95CAEE299DCEF1009DCB67 /* KFOptionSetter+.swift in Sources */,
|
||||||
4C7D09722A0AEF5E00943473 /* DamusGradient.swift in Sources */,
|
4C7D09722A0AEF5E00943473 /* DamusGradient.swift in Sources */,
|
||||||
4C463CBF2B960B96008A8C36 /* PurpleBackdrop.swift in Sources */,
|
4C463CBF2B960B96008A8C36 /* PurpleBackdrop.swift in Sources */,
|
||||||
|
5C8F97502EBD704A009399B1 /* LabsToggleView.swift in Sources */,
|
||||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */,
|
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */,
|
||||||
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
||||||
4CF4803A2B631C0100F2B2C0 /* nostr_bech32.c in Sources */,
|
4CF4803A2B631C0100F2B2C0 /* nostr_bech32.c in Sources */,
|
||||||
@@ -5773,12 +5942,14 @@
|
|||||||
4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */,
|
4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */,
|
||||||
D78F08142D7F78F900FC6C75 /* Response.swift in Sources */,
|
D78F08142D7F78F900FC6C75 /* Response.swift in Sources */,
|
||||||
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
||||||
|
5C8F97372EB46145009399B1 /* LiveStreamView.swift in Sources */,
|
||||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
||||||
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
||||||
5CC852A22BDED9B90039FFC5 /* HighlightDescription.swift in Sources */,
|
5CC852A22BDED9B90039FFC5 /* HighlightDescription.swift in Sources */,
|
||||||
4C94D6432BA5AEFE00C26EFF /* QuoteRepostsView.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 */,
|
||||||
|
5C8F97422EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */,
|
||||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
||||||
4CE879582996C45300F758CC /* ZapsView.swift in Sources */,
|
4CE879582996C45300F758CC /* ZapsView.swift in Sources */,
|
||||||
4C30AC7429A5680900E2BD5A /* EventGroupView.swift in Sources */,
|
4C30AC7429A5680900E2BD5A /* EventGroupView.swift in Sources */,
|
||||||
@@ -5829,11 +6000,13 @@
|
|||||||
4CA352A22A76AEC5003BB08B /* LikedNotify.swift in Sources */,
|
4CA352A22A76AEC5003BB08B /* LikedNotify.swift in Sources */,
|
||||||
5CC8529F2BD744F60039FFC5 /* HighlightView.swift in Sources */,
|
5CC8529F2BD744F60039FFC5 /* HighlightView.swift in Sources */,
|
||||||
BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */,
|
BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */,
|
||||||
|
5C8F97462EB461DB009399B1 /* EventTags.swift in Sources */,
|
||||||
3A515C562DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */,
|
3A515C562DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */,
|
||||||
5CC8529D2BD741CD0039FFC5 /* HighlightEvent.swift in Sources */,
|
5CC8529D2BD741CD0039FFC5 /* HighlightEvent.swift in Sources */,
|
||||||
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
||||||
4CF480422B631C0100F2B2C0 /* NdbProfile.swift in Sources */,
|
4CF480422B631C0100F2B2C0 /* NdbProfile.swift in Sources */,
|
||||||
4CA9276C2A2910D10098A105 /* ReplyPart.swift in Sources */,
|
4CA9276C2A2910D10098A105 /* ReplyPart.swift in Sources */,
|
||||||
|
5C8F97102EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */,
|
||||||
D7C6787E2B2D34CC00BCEAFB /* NIP98AuthenticatedRequest.swift in Sources */,
|
D7C6787E2B2D34CC00BCEAFB /* NIP98AuthenticatedRequest.swift in Sources */,
|
||||||
5CB017252D42C5C400A9ED05 /* TransactionsView.swift in Sources */,
|
5CB017252D42C5C400A9ED05 /* TransactionsView.swift in Sources */,
|
||||||
4CE1399029F0661A00AC6A0B /* RepostAction.swift in Sources */,
|
4CE1399029F0661A00AC6A0B /* RepostAction.swift in Sources */,
|
||||||
@@ -5860,11 +6033,13 @@
|
|||||||
D73FA9E12DDC12AA00C706E1 /* OnboardingContentSettings.swift in Sources */,
|
D73FA9E12DDC12AA00C706E1 /* OnboardingContentSettings.swift in Sources */,
|
||||||
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */,
|
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */,
|
||||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
||||||
|
5C8F97132EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */,
|
||||||
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayer.swift in Sources */,
|
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayer.swift in Sources */,
|
||||||
4CF480552B631C4F00F2B2C0 /* wasm.c in Sources */,
|
4CF480552B631C4F00F2B2C0 /* wasm.c in Sources */,
|
||||||
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayer.swift in Sources */,
|
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayer.swift in Sources */,
|
||||||
4CFF8F6B29CD0079008DB934 /* RepostedEvent.swift in Sources */,
|
4CFF8F6B29CD0079008DB934 /* RepostedEvent.swift in Sources */,
|
||||||
D78CD5982B8990300014D539 /* DamusAppNotificationView.swift in Sources */,
|
D78CD5982B8990300014D539 /* DamusAppNotificationView.swift in Sources */,
|
||||||
|
5C8F972B2EB460E6009399B1 /* LiveStreamProfile.swift in Sources */,
|
||||||
D724D8272B64B40B00ABE789 /* DamusPurpleAccountView.swift in Sources */,
|
D724D8272B64B40B00ABE789 /* DamusPurpleAccountView.swift in Sources */,
|
||||||
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
||||||
5C0707D12A1ECB38004E7B51 /* DamusLogoGradient.swift in Sources */,
|
5C0707D12A1ECB38004E7B51 /* DamusLogoGradient.swift in Sources */,
|
||||||
@@ -5923,6 +6098,7 @@
|
|||||||
4C1253562A76C8C60004F4B8 /* BroadcastNotify.swift in Sources */,
|
4C1253562A76C8C60004F4B8 /* BroadcastNotify.swift in Sources */,
|
||||||
4CF480392B631C0100F2B2C0 /* block.c in Sources */,
|
4CF480392B631C0100F2B2C0 /* block.c in Sources */,
|
||||||
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
||||||
|
5C8F973F2EB46197009399B1 /* LiveStreamPreview.swift in Sources */,
|
||||||
B533694E2B66D791008A805E /* MutelistManager.swift in Sources */,
|
B533694E2B66D791008A805E /* MutelistManager.swift in Sources */,
|
||||||
4C32B9532A9AD44700DC3548 /* Verifier.swift in Sources */,
|
4C32B9532A9AD44700DC3548 /* Verifier.swift in Sources */,
|
||||||
5C14C29D2BBBA40B00079FD2 /* RelayAdminDetail.swift in Sources */,
|
5C14C29D2BBBA40B00079FD2 /* RelayAdminDetail.swift in Sources */,
|
||||||
@@ -5945,6 +6121,7 @@
|
|||||||
E0EE9DD42B8E5FEA00F3002D /* ImageProcessing.swift in Sources */,
|
E0EE9DD42B8E5FEA00F3002D /* ImageProcessing.swift in Sources */,
|
||||||
4CB883B0297705DD00DC99E7 /* NoteZapButton.swift in Sources */,
|
4CB883B0297705DD00DC99E7 /* NoteZapButton.swift in Sources */,
|
||||||
D7DF58342DFCF18D00E9AD28 /* SendPaymentView.swift in Sources */,
|
D7DF58342DFCF18D00E9AD28 /* SendPaymentView.swift in Sources */,
|
||||||
|
5C8F970A2EB45E8C009399B1 /* LiveChatModel.swift in Sources */,
|
||||||
4C363A922825FCF2006E126D /* ProfileUpdate.swift in Sources */,
|
4C363A922825FCF2006E126D /* ProfileUpdate.swift in Sources */,
|
||||||
4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
|
4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
|
||||||
4C32B9502A9AD44700DC3548 /* FlatBufferBuilder.swift in Sources */,
|
4C32B9502A9AD44700DC3548 /* FlatBufferBuilder.swift in Sources */,
|
||||||
@@ -5964,9 +6141,10 @@
|
|||||||
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
|
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
|
||||||
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
|
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
|
||||||
D5C1AFD42E5EE2820092F72F /* FavoriteButtonView.swift in Sources */,
|
D5C1AFD42E5EE2820092F72F /* FavoriteButtonView.swift in Sources */,
|
||||||
5CB645AB2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
|
5CB645AB2EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */,
|
||||||
D5C1AFCA2E5EE12B0092F72F /* ContactCardNotify.swift in Sources */,
|
D5C1AFCA2E5EE12B0092F72F /* ContactCardNotify.swift in Sources */,
|
||||||
4CA352A82A76B37E003BB08B /* NewMutesNotify.swift in Sources */,
|
4CA352A82A76B37E003BB08B /* NewMutesNotify.swift in Sources */,
|
||||||
|
5C8F974A2EB4620A009399B1 /* Glow.swift in Sources */,
|
||||||
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 */,
|
||||||
@@ -5995,9 +6173,11 @@
|
|||||||
4C1253622A76D00B0004F4B8 /* PostNotify.swift in Sources */,
|
4C1253622A76D00B0004F4B8 /* PostNotify.swift in Sources */,
|
||||||
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */,
|
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */,
|
||||||
5CB017232D2D985E00A9ED05 /* CoinosButton.swift in Sources */,
|
5CB017232D2D985E00A9ED05 /* CoinosButton.swift in Sources */,
|
||||||
|
5C8F973B2EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */,
|
||||||
F7908E92298B0F0700AB113A /* RelayDetailView.swift in Sources */,
|
F7908E92298B0F0700AB113A /* RelayDetailView.swift in Sources */,
|
||||||
4CE879552996BAB900F758CC /* RelayPaidDetail.swift in Sources */,
|
4CE879552996BAB900F758CC /* RelayPaidDetail.swift in Sources */,
|
||||||
5CB0172F2D42C76A00A9ED05 /* BalanceView.swift in Sources */,
|
5CB0172F2D42C76A00A9ED05 /* BalanceView.swift in Sources */,
|
||||||
|
5C8F971D2EB4607B009399B1 /* LiveEvent.swift in Sources */,
|
||||||
4C1253602A76CF890004F4B8 /* ScrollToTopNotify.swift in Sources */,
|
4C1253602A76CF890004F4B8 /* ScrollToTopNotify.swift in Sources */,
|
||||||
4CA3529E2A76AE67003BB08B /* FollowNotify.swift in Sources */,
|
4CA3529E2A76AE67003BB08B /* FollowNotify.swift in Sources */,
|
||||||
4CF0ABD42980996B00D66079 /* Report.swift in Sources */,
|
4CF0ABD42980996B00D66079 /* Report.swift in Sources */,
|
||||||
@@ -6132,7 +6312,7 @@
|
|||||||
5C4FA7FB2DC29C3800CE658C /* FollowPackView.swift in Sources */,
|
5C4FA7FB2DC29C3800CE658C /* FollowPackView.swift in Sources */,
|
||||||
4C3624722D5EA18E00DD066E /* amount.c in Sources */,
|
4C3624722D5EA18E00DD066E /* amount.c in Sources */,
|
||||||
4C3624712D5EA18300DD066E /* error.c in Sources */,
|
4C3624712D5EA18300DD066E /* error.c in Sources */,
|
||||||
5CB645A92EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
|
5CB645A92EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */,
|
||||||
4C3624702D5EA17700DD066E /* utf8.c in Sources */,
|
4C3624702D5EA17700DD066E /* utf8.c in Sources */,
|
||||||
4C36246F2D5EA16A00DD066E /* str.c in Sources */,
|
4C36246F2D5EA16A00DD066E /* str.c in Sources */,
|
||||||
4C36246E2D5EA10400DD066E /* hash_u5.c in Sources */,
|
4C36246E2D5EA10400DD066E /* hash_u5.c in Sources */,
|
||||||
@@ -6155,6 +6335,7 @@
|
|||||||
82D6FA9A2CD9820500C925F4 /* ShareViewController.swift in Sources */,
|
82D6FA9A2CD9820500C925F4 /* ShareViewController.swift in Sources */,
|
||||||
82D6FAA92CD99F7900C925F4 /* FbConstants.swift in Sources */,
|
82D6FAA92CD99F7900C925F4 /* FbConstants.swift in Sources */,
|
||||||
82D6FAAA2CD99F7900C925F4 /* Offset.swift in Sources */,
|
82D6FAAA2CD99F7900C925F4 /* Offset.swift in Sources */,
|
||||||
|
5C8F97322EB46126009399B1 /* LiveStreamViewers.swift in Sources */,
|
||||||
82D6FAAB2CD99F7900C925F4 /* Int+extension.swift in Sources */,
|
82D6FAAB2CD99F7900C925F4 /* Int+extension.swift in Sources */,
|
||||||
82D6FAAC2CD99F7900C925F4 /* FlatBufferBuilder.swift in Sources */,
|
82D6FAAC2CD99F7900C925F4 /* FlatBufferBuilder.swift in Sources */,
|
||||||
82D6FAAD2CD99F7900C925F4 /* FlatbuffersErrors.swift in Sources */,
|
82D6FAAD2CD99F7900C925F4 /* FlatbuffersErrors.swift in Sources */,
|
||||||
@@ -6290,13 +6471,16 @@
|
|||||||
82D6FB2E2CD99F7900C925F4 /* BlurHashEncode.swift in Sources */,
|
82D6FB2E2CD99F7900C925F4 /* BlurHashEncode.swift in Sources */,
|
||||||
82D6FB2F2CD99F7900C925F4 /* BlurHashDecode.swift in Sources */,
|
82D6FB2F2CD99F7900C925F4 /* BlurHashDecode.swift in Sources */,
|
||||||
82D6FB302CD99F7900C925F4 /* PostBox.swift in Sources */,
|
82D6FB302CD99F7900C925F4 /* PostBox.swift in Sources */,
|
||||||
|
5C8F970B2EB45E8C009399B1 /* LiveChatModel.swift in Sources */,
|
||||||
82D6FB312CD99F7900C925F4 /* KFOptionSetter+.swift in Sources */,
|
82D6FB312CD99F7900C925F4 /* KFOptionSetter+.swift in Sources */,
|
||||||
|
5C8F972F2EB46116009399B1 /* LiveStreamStatus.swift in Sources */,
|
||||||
D73BDB162D71216500D69970 /* UserRelayListManager.swift in Sources */,
|
D73BDB162D71216500D69970 /* UserRelayListManager.swift in Sources */,
|
||||||
82D6FB322CD99F7900C925F4 /* FillAndStroke.swift in Sources */,
|
82D6FB322CD99F7900C925F4 /* FillAndStroke.swift in Sources */,
|
||||||
82D6FB332CD99F7900C925F4 /* Array.swift in Sources */,
|
82D6FB332CD99F7900C925F4 /* Array.swift in Sources */,
|
||||||
82D6FB342CD99F7900C925F4 /* VectorMath.swift in Sources */,
|
82D6FB342CD99F7900C925F4 /* VectorMath.swift in Sources */,
|
||||||
5C8498022D5D150000F74FEB /* ZapExplainer.swift in Sources */,
|
5C8498022D5D150000F74FEB /* ZapExplainer.swift in Sources */,
|
||||||
82D6FB352CD99F7900C925F4 /* OffsetExtension.swift in Sources */,
|
82D6FB352CD99F7900C925F4 /* OffsetExtension.swift in Sources */,
|
||||||
|
5C8F973A2EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */,
|
||||||
82D6FB362CD99F7900C925F4 /* RelayFilters.swift in Sources */,
|
82D6FB362CD99F7900C925F4 /* RelayFilters.swift in Sources */,
|
||||||
82D6FB372CD99F7900C925F4 /* RelayModelCache.swift in Sources */,
|
82D6FB372CD99F7900C925F4 /* RelayModelCache.swift in Sources */,
|
||||||
82D6FB382CD99F7900C925F4 /* RelayBootstrap.swift in Sources */,
|
82D6FB382CD99F7900C925F4 /* RelayBootstrap.swift in Sources */,
|
||||||
@@ -6343,6 +6527,7 @@
|
|||||||
82D6FB5F2CD99F7900C925F4 /* KeyboardVisible.swift in Sources */,
|
82D6FB5F2CD99F7900C925F4 /* KeyboardVisible.swift in Sources */,
|
||||||
82D6FB602CD99F7900C925F4 /* StringUtil.swift in Sources */,
|
82D6FB602CD99F7900C925F4 /* StringUtil.swift in Sources */,
|
||||||
D78F08172D7F7F7500FC6C75 /* NIP04.swift in Sources */,
|
D78F08172D7F7F7500FC6C75 /* NIP04.swift in Sources */,
|
||||||
|
5C8F973E2EB46197009399B1 /* LiveStreamPreview.swift in Sources */,
|
||||||
82D6FB612CD99F7900C925F4 /* Router.swift in Sources */,
|
82D6FB612CD99F7900C925F4 /* Router.swift in Sources */,
|
||||||
82D6FB622CD99F7900C925F4 /* Log.swift in Sources */,
|
82D6FB622CD99F7900C925F4 /* Log.swift in Sources */,
|
||||||
82D6FB632CD99F7900C925F4 /* AVPlayer+Additions.swift in Sources */,
|
82D6FB632CD99F7900C925F4 /* AVPlayer+Additions.swift in Sources */,
|
||||||
@@ -6408,6 +6593,7 @@
|
|||||||
82D6FB9B2CD99F7900C925F4 /* MutedThreadsManager.swift in Sources */,
|
82D6FB9B2CD99F7900C925F4 /* MutedThreadsManager.swift in Sources */,
|
||||||
82D6FB9C2CD99F7900C925F4 /* WalletModel.swift in Sources */,
|
82D6FB9C2CD99F7900C925F4 /* WalletModel.swift in Sources */,
|
||||||
82D6FB9D2CD99F7900C925F4 /* ZapButtonModel.swift in Sources */,
|
82D6FB9D2CD99F7900C925F4 /* ZapButtonModel.swift in Sources */,
|
||||||
|
5C8F97432EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */,
|
||||||
5C09FD142DF283D700823661 /* FollowPackModel.swift in Sources */,
|
5C09FD142DF283D700823661 /* FollowPackModel.swift in Sources */,
|
||||||
82D6FB9E2CD99F7900C925F4 /* ContentFilters.swift in Sources */,
|
82D6FB9E2CD99F7900C925F4 /* ContentFilters.swift in Sources */,
|
||||||
3A515C512DF4E100002D3B34 /* TrustedNetworkRepliesTip.swift in Sources */,
|
3A515C512DF4E100002D3B34 /* TrustedNetworkRepliesTip.swift in Sources */,
|
||||||
@@ -6419,6 +6605,7 @@
|
|||||||
82D6FBA32CD99F7900C925F4 /* NewEventsBits.swift in Sources */,
|
82D6FBA32CD99F7900C925F4 /* NewEventsBits.swift in Sources */,
|
||||||
82D6FBA42CD99F7900C925F4 /* FriendFilter.swift in Sources */,
|
82D6FBA42CD99F7900C925F4 /* FriendFilter.swift in Sources */,
|
||||||
82D6FBA52CD99F7900C925F4 /* MediaUploader.swift in Sources */,
|
82D6FBA52CD99F7900C925F4 /* MediaUploader.swift in Sources */,
|
||||||
|
5C8F974F2EBD704A009399B1 /* LabsToggleView.swift in Sources */,
|
||||||
82D6FBA62CD99F7900C925F4 /* FollowState.swift in Sources */,
|
82D6FBA62CD99F7900C925F4 /* FollowState.swift in Sources */,
|
||||||
82D6FBA72CD99F7900C925F4 /* NoteContent.swift in Sources */,
|
82D6FBA72CD99F7900C925F4 /* NoteContent.swift in Sources */,
|
||||||
82D6FBA82CD99F7900C925F4 /* LongformEvent.swift in Sources */,
|
82D6FBA82CD99F7900C925F4 /* LongformEvent.swift in Sources */,
|
||||||
@@ -6470,6 +6657,7 @@
|
|||||||
82D6FBD62CD99F7900C925F4 /* WalletView.swift in Sources */,
|
82D6FBD62CD99F7900C925F4 /* WalletView.swift in Sources */,
|
||||||
82D6FBD72CD99F7900C925F4 /* NWCScannerView.swift in Sources */,
|
82D6FBD72CD99F7900C925F4 /* NWCScannerView.swift in Sources */,
|
||||||
82D6FBD82CD99F7900C925F4 /* TrustedNetworkButton.swift in Sources */,
|
82D6FBD82CD99F7900C925F4 /* TrustedNetworkButton.swift in Sources */,
|
||||||
|
5C8F971E2EB4607B009399B1 /* LiveEvent.swift in Sources */,
|
||||||
82D6FBD92CD99F7900C925F4 /* GradientFollowButton.swift in Sources */,
|
82D6FBD92CD99F7900C925F4 /* GradientFollowButton.swift in Sources */,
|
||||||
82D6FBDC2CD99F7900C925F4 /* DamusVideoPlayerView.swift in Sources */,
|
82D6FBDC2CD99F7900C925F4 /* DamusVideoPlayerView.swift in Sources */,
|
||||||
82D6FBDD2CD99F7900C925F4 /* DamusVideoPlayer.swift in Sources */,
|
82D6FBDD2CD99F7900C925F4 /* DamusVideoPlayer.swift in Sources */,
|
||||||
@@ -6481,6 +6669,7 @@
|
|||||||
82D6FBE32CD99F7900C925F4 /* KeySettingsView.swift in Sources */,
|
82D6FBE32CD99F7900C925F4 /* KeySettingsView.swift in Sources */,
|
||||||
82D6FBE42CD99F7900C925F4 /* ZapSettingsView.swift in Sources */,
|
82D6FBE42CD99F7900C925F4 /* ZapSettingsView.swift in Sources */,
|
||||||
82D6FBE52CD99F7900C925F4 /* TranslationSettingsView.swift in Sources */,
|
82D6FBE52CD99F7900C925F4 /* TranslationSettingsView.swift in Sources */,
|
||||||
|
5C8F97472EB461DB009399B1 /* EventTags.swift in Sources */,
|
||||||
82D6FBE62CD99F7900C925F4 /* SearchSettingsView.swift in Sources */,
|
82D6FBE62CD99F7900C925F4 /* SearchSettingsView.swift in Sources */,
|
||||||
82D6FBE72CD99F7900C925F4 /* DeveloperSettingsView.swift in Sources */,
|
82D6FBE72CD99F7900C925F4 /* DeveloperSettingsView.swift in Sources */,
|
||||||
82D6FBE82CD99F7900C925F4 /* FirstAidSettingsView.swift in Sources */,
|
82D6FBE82CD99F7900C925F4 /* FirstAidSettingsView.swift in Sources */,
|
||||||
@@ -6489,6 +6678,7 @@
|
|||||||
D7F360272CEBBDC0009D34DA /* DamusVideoControlsView.swift in Sources */,
|
D7F360272CEBBDC0009D34DA /* DamusVideoControlsView.swift in Sources */,
|
||||||
82D6FBEB2CD99F7900C925F4 /* ProfilePicImageView.swift in Sources */,
|
82D6FBEB2CD99F7900C925F4 /* ProfilePicImageView.swift in Sources */,
|
||||||
82D6FBEC2CD99F7900C925F4 /* ImageContainerView.swift in Sources */,
|
82D6FBEC2CD99F7900C925F4 /* ImageContainerView.swift in Sources */,
|
||||||
|
5C8F97492EB4620A009399B1 /* Glow.swift in Sources */,
|
||||||
82D6FBED2CD99F7900C925F4 /* MediaView.swift in Sources */,
|
82D6FBED2CD99F7900C925F4 /* MediaView.swift in Sources */,
|
||||||
82D6FBEE2CD99F7900C925F4 /* PurpleViewPrimitives.swift in Sources */,
|
82D6FBEE2CD99F7900C925F4 /* PurpleViewPrimitives.swift in Sources */,
|
||||||
82D6FBEF2CD99F7900C925F4 /* MarketingContentView.swift in Sources */,
|
82D6FBEF2CD99F7900C925F4 /* MarketingContentView.swift in Sources */,
|
||||||
@@ -6496,8 +6686,10 @@
|
|||||||
82D6FBF02CD99F7900C925F4 /* LogoView.swift in Sources */,
|
82D6FBF02CD99F7900C925F4 /* LogoView.swift in Sources */,
|
||||||
82D6FBF12CD99F7900C925F4 /* IAPProductStateView.swift in Sources */,
|
82D6FBF12CD99F7900C925F4 /* IAPProductStateView.swift in Sources */,
|
||||||
D74DEC8B2DA0A19B00E69FA6 /* Ndb+.swift in Sources */,
|
D74DEC8B2DA0A19B00E69FA6 /* Ndb+.swift in Sources */,
|
||||||
|
5C8F97252EB460CA009399B1 /* LiveStreamBanner.swift in Sources */,
|
||||||
82D6FBF22CD99F7900C925F4 /* PurpleBackdrop.swift in Sources */,
|
82D6FBF22CD99F7900C925F4 /* PurpleBackdrop.swift in Sources */,
|
||||||
82D6FBF32CD99F7900C925F4 /* DamusPurpleView.swift in Sources */,
|
82D6FBF32CD99F7900C925F4 /* DamusPurpleView.swift in Sources */,
|
||||||
|
5C8F972A2EB460E6009399B1 /* LiveStreamProfile.swift in Sources */,
|
||||||
82D6FBF42CD99F7900C925F4 /* DamusPurpleWelcomeView.swift in Sources */,
|
82D6FBF42CD99F7900C925F4 /* DamusPurpleWelcomeView.swift in Sources */,
|
||||||
82D6FBF52CD99F7900C925F4 /* DamusPurpleTranslationSetupView.swift in Sources */,
|
82D6FBF52CD99F7900C925F4 /* DamusPurpleTranslationSetupView.swift in Sources */,
|
||||||
82D6FBF62CD99F7900C925F4 /* DamusPurpleURLSheetView.swift in Sources */,
|
82D6FBF62CD99F7900C925F4 /* DamusPurpleURLSheetView.swift in Sources */,
|
||||||
@@ -6520,6 +6712,7 @@
|
|||||||
82D6FC062CD99F7900C925F4 /* ZapTypePicker.swift in Sources */,
|
82D6FC062CD99F7900C925F4 /* ZapTypePicker.swift in Sources */,
|
||||||
82D6FC072CD99F7900C925F4 /* ZapUserView.swift in Sources */,
|
82D6FC072CD99F7900C925F4 /* ZapUserView.swift in Sources */,
|
||||||
82D6FC082CD99F7900C925F4 /* ProfileZapLinkView.swift in Sources */,
|
82D6FC082CD99F7900C925F4 /* ProfileZapLinkView.swift in Sources */,
|
||||||
|
5C8F970E2EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */,
|
||||||
D71AD8FE2CEC176A002E2C3C /* AppAccessibilityIdentifiers.swift in Sources */,
|
D71AD8FE2CEC176A002E2C3C /* AppAccessibilityIdentifiers.swift in Sources */,
|
||||||
82D6FC092CD99F7900C925F4 /* AboutView.swift in Sources */,
|
82D6FC092CD99F7900C925F4 /* AboutView.swift in Sources */,
|
||||||
D72C01332E78C10500AACB67 /* CondensedProfilePicturesViewModel.swift in Sources */,
|
D72C01332E78C10500AACB67 /* CondensedProfilePicturesViewModel.swift in Sources */,
|
||||||
@@ -6568,8 +6761,10 @@
|
|||||||
82D6FC2E2CD99F7900C925F4 /* ReplyDescription.swift in Sources */,
|
82D6FC2E2CD99F7900C925F4 /* ReplyDescription.swift in Sources */,
|
||||||
82D6FC2F2CD99F7900C925F4 /* RelativeTime.swift in Sources */,
|
82D6FC2F2CD99F7900C925F4 /* RelativeTime.swift in Sources */,
|
||||||
82D6FC302CD99F7900C925F4 /* ReplyPart.swift in Sources */,
|
82D6FC302CD99F7900C925F4 /* ReplyPart.swift in Sources */,
|
||||||
|
5C8F97532EBD7083009399B1 /* LabsExplainerView.swift in Sources */,
|
||||||
82D6FC312CD99F7900C925F4 /* ProxyView.swift in Sources */,
|
82D6FC312CD99F7900C925F4 /* ProxyView.swift in Sources */,
|
||||||
82D6FC322CD99F7900C925F4 /* SelectedEventView.swift in Sources */,
|
82D6FC322CD99F7900C925F4 /* SelectedEventView.swift in Sources */,
|
||||||
|
5C8F97352EB46145009399B1 /* LiveStreamView.swift in Sources */,
|
||||||
82D6FC332CD99F7900C925F4 /* EventBody.swift in Sources */,
|
82D6FC332CD99F7900C925F4 /* EventBody.swift in Sources */,
|
||||||
D5C1AFC02E5DF7E60092F72F /* ContactCardManager.swift in Sources */,
|
D5C1AFC02E5DF7E60092F72F /* ContactCardManager.swift in Sources */,
|
||||||
82D6FC342CD99F7900C925F4 /* BuilderEventView.swift in Sources */,
|
82D6FC342CD99F7900C925F4 /* BuilderEventView.swift in Sources */,
|
||||||
@@ -6585,6 +6780,7 @@
|
|||||||
82D6FC3D2CD99F7900C925F4 /* EventShell.swift in Sources */,
|
82D6FC3D2CD99F7900C925F4 /* EventShell.swift in Sources */,
|
||||||
82D6FC3E2CD99F7900C925F4 /* MentionView.swift in Sources */,
|
82D6FC3E2CD99F7900C925F4 /* MentionView.swift in Sources */,
|
||||||
82D6FC3F2CD99F7900C925F4 /* EventLoaderView.swift in Sources */,
|
82D6FC3F2CD99F7900C925F4 /* EventLoaderView.swift in Sources */,
|
||||||
|
5C8F97122EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */,
|
||||||
82D6FC402CD99F7900C925F4 /* RepostView.swift in Sources */,
|
82D6FC402CD99F7900C925F4 /* RepostView.swift in Sources */,
|
||||||
82D6FC412CD99F7900C925F4 /* RepostedEvent.swift in Sources */,
|
82D6FC412CD99F7900C925F4 /* RepostedEvent.swift in Sources */,
|
||||||
82D6FC422CD99F7900C925F4 /* QuoteRepostsView.swift in Sources */,
|
82D6FC422CD99F7900C925F4 /* QuoteRepostsView.swift in Sources */,
|
||||||
@@ -6609,6 +6805,7 @@
|
|||||||
82D6FC532CD99F7900C925F4 /* EmptyTimelineView.swift in Sources */,
|
82D6FC532CD99F7900C925F4 /* EmptyTimelineView.swift in Sources */,
|
||||||
82D6FC542CD99F7900C925F4 /* EmptyUserSearchView.swift in Sources */,
|
82D6FC542CD99F7900C925F4 /* EmptyUserSearchView.swift in Sources */,
|
||||||
D706C5B82D602A110027C627 /* QueueableNotify.swift in Sources */,
|
D706C5B82D602A110027C627 /* QueueableNotify.swift in Sources */,
|
||||||
|
5C8F97182EB45FD7009399B1 /* LiveChatView.swift in Sources */,
|
||||||
82D6FC552CD99F7900C925F4 /* EventView.swift in Sources */,
|
82D6FC552CD99F7900C925F4 /* EventView.swift in Sources */,
|
||||||
82D6FC562CD99F7900C925F4 /* EventDetailView.swift in Sources */,
|
82D6FC562CD99F7900C925F4 /* EventDetailView.swift in Sources */,
|
||||||
82D6FC572CD99F7900C925F4 /* FollowButtonView.swift in Sources */,
|
82D6FC572CD99F7900C925F4 /* FollowButtonView.swift in Sources */,
|
||||||
@@ -6625,6 +6822,7 @@
|
|||||||
82D6FC612CD99F7900C925F4 /* MainTabView.swift in Sources */,
|
82D6FC612CD99F7900C925F4 /* MainTabView.swift in Sources */,
|
||||||
82D6FC622CD99F7900C925F4 /* PubkeyView.swift in Sources */,
|
82D6FC622CD99F7900C925F4 /* PubkeyView.swift in Sources */,
|
||||||
D7F360252CEBBD7E009D34DA /* DamusFullScreenCover.swift in Sources */,
|
D7F360252CEBBD7E009D34DA /* DamusFullScreenCover.swift in Sources */,
|
||||||
|
5C8F97212EB46097009399B1 /* LiveEventModel.swift in Sources */,
|
||||||
82D6FC632CD99F7900C925F4 /* ReplyView.swift in Sources */,
|
82D6FC632CD99F7900C925F4 /* ReplyView.swift in Sources */,
|
||||||
82D6FC642CD99F7900C925F4 /* ParticipantsView.swift in Sources */,
|
82D6FC642CD99F7900C925F4 /* ParticipantsView.swift in Sources */,
|
||||||
82D6FC652CD99F7900C925F4 /* SaveKeysView.swift in Sources */,
|
82D6FC652CD99F7900C925F4 /* SaveKeysView.swift in Sources */,
|
||||||
@@ -6660,6 +6858,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C36247D2D5EA22300DD066E /* invoice.c in Sources */,
|
4C36247D2D5EA22300DD066E /* invoice.c in Sources */,
|
||||||
|
5C8F974E2EBD704A009399B1 /* LabsToggleView.swift in Sources */,
|
||||||
4C36247C2D5EA21F00DD066E /* amount.c in Sources */,
|
4C36247C2D5EA21F00DD066E /* amount.c in Sources */,
|
||||||
4C36247B2D5EA21200DD066E /* hash_u5.c in Sources */,
|
4C36247B2D5EA21200DD066E /* hash_u5.c in Sources */,
|
||||||
4C36247A2D5EA20C00DD066E /* bech32.c in Sources */,
|
4C36247A2D5EA20C00DD066E /* bech32.c in Sources */,
|
||||||
@@ -6702,6 +6901,7 @@
|
|||||||
D73E5E352C6A97F4007EB227 /* RelaysChangedNotify.swift in Sources */,
|
D73E5E352C6A97F4007EB227 /* RelaysChangedNotify.swift in Sources */,
|
||||||
D73E5E362C6A97F4007EB227 /* MuteThreadNotify.swift in Sources */,
|
D73E5E362C6A97F4007EB227 /* MuteThreadNotify.swift in Sources */,
|
||||||
D73E5E372C6A97F4007EB227 /* ReconnectRelaysNotify.swift in Sources */,
|
D73E5E372C6A97F4007EB227 /* ReconnectRelaysNotify.swift in Sources */,
|
||||||
|
5C8F97202EB46097009399B1 /* LiveEventModel.swift in Sources */,
|
||||||
D73E5E382C6A97F4007EB227 /* PurpleAccountUpdateNotify.swift in Sources */,
|
D73E5E382C6A97F4007EB227 /* PurpleAccountUpdateNotify.swift in Sources */,
|
||||||
D73E5E392C6A97F4007EB227 /* DamusDuration.swift in Sources */,
|
D73E5E392C6A97F4007EB227 /* DamusDuration.swift in Sources */,
|
||||||
D73E5E3A2C6A97F4007EB227 /* SwipeToDismiss.swift in Sources */,
|
D73E5E3A2C6A97F4007EB227 /* SwipeToDismiss.swift in Sources */,
|
||||||
@@ -6745,6 +6945,7 @@
|
|||||||
D73E5E622C6A97F4007EB227 /* BlurHashEncode.swift in Sources */,
|
D73E5E622C6A97F4007EB227 /* BlurHashEncode.swift in Sources */,
|
||||||
5C09FD122DF283D700823661 /* FollowPackModel.swift in Sources */,
|
5C09FD122DF283D700823661 /* FollowPackModel.swift in Sources */,
|
||||||
D73E5E632C6A97F4007EB227 /* BlurHashDecode.swift in Sources */,
|
D73E5E632C6A97F4007EB227 /* BlurHashDecode.swift in Sources */,
|
||||||
|
5C8F97542EBD7083009399B1 /* LabsExplainerView.swift in Sources */,
|
||||||
D74EC8522E1856B70091DC51 /* NonCopyableLinkedList.swift in Sources */,
|
D74EC8522E1856B70091DC51 /* NonCopyableLinkedList.swift in Sources */,
|
||||||
D73E5F952C6AA753007EB227 /* FullScreenCarouselView.swift in Sources */,
|
D73E5F952C6AA753007EB227 /* FullScreenCarouselView.swift in Sources */,
|
||||||
D76BE18E2E0CF3DA004AD0C6 /* Interests.swift in Sources */,
|
D76BE18E2E0CF3DA004AD0C6 /* Interests.swift in Sources */,
|
||||||
@@ -6783,6 +6984,7 @@
|
|||||||
D73E5E7F2C6A97F4007EB227 /* LocalNotification.swift in Sources */,
|
D73E5E7F2C6A97F4007EB227 /* LocalNotification.swift in Sources */,
|
||||||
D73E5E802C6A97F4007EB227 /* CredentialHandler.swift in Sources */,
|
D73E5E802C6A97F4007EB227 /* CredentialHandler.swift in Sources */,
|
||||||
D73E5E812C6A97F4007EB227 /* KeyboardVisible.swift in Sources */,
|
D73E5E812C6A97F4007EB227 /* KeyboardVisible.swift in Sources */,
|
||||||
|
5C8F971C2EB4607B009399B1 /* LiveEvent.swift in Sources */,
|
||||||
D73E5E832C6A97F4007EB227 /* AVPlayer+Additions.swift in Sources */,
|
D73E5E832C6A97F4007EB227 /* AVPlayer+Additions.swift in Sources */,
|
||||||
5C4FA7FC2DC29C3800CE658C /* FollowPackView.swift in Sources */,
|
5C4FA7FC2DC29C3800CE658C /* FollowPackView.swift in Sources */,
|
||||||
D73E5E842C6A97F4007EB227 /* Zaps+.swift in Sources */,
|
D73E5E842C6A97F4007EB227 /* Zaps+.swift in Sources */,
|
||||||
@@ -6852,6 +7054,7 @@
|
|||||||
D73E5EAD2C6A97F4007EB227 /* MutedThreadsManager.swift in Sources */,
|
D73E5EAD2C6A97F4007EB227 /* MutedThreadsManager.swift in Sources */,
|
||||||
D73E5EAE2C6A97F4007EB227 /* WalletModel.swift in Sources */,
|
D73E5EAE2C6A97F4007EB227 /* WalletModel.swift in Sources */,
|
||||||
D73E5EAF2C6A97F4007EB227 /* ZapButtonModel.swift in Sources */,
|
D73E5EAF2C6A97F4007EB227 /* ZapButtonModel.swift in Sources */,
|
||||||
|
5C8F97292EB460E6009399B1 /* LiveStreamProfile.swift in Sources */,
|
||||||
D73E5EB02C6A97F4007EB227 /* ContentFilters.swift in Sources */,
|
D73E5EB02C6A97F4007EB227 /* ContentFilters.swift in Sources */,
|
||||||
D73E5EB12C6A97F4007EB227 /* DamusCacheManager.swift in Sources */,
|
D73E5EB12C6A97F4007EB227 /* DamusCacheManager.swift in Sources */,
|
||||||
D73E5EB22C6A97F4007EB227 /* NotificationsManager.swift in Sources */,
|
D73E5EB22C6A97F4007EB227 /* NotificationsManager.swift in Sources */,
|
||||||
@@ -6874,6 +7077,7 @@
|
|||||||
D73E5EBE2C6A97F4007EB227 /* NostrLink.swift in Sources */,
|
D73E5EBE2C6A97F4007EB227 /* NostrLink.swift in Sources */,
|
||||||
D73E5EBF2C6A97F4007EB227 /* WebSocket.swift in Sources */,
|
D73E5EBF2C6A97F4007EB227 /* WebSocket.swift in Sources */,
|
||||||
D73E5F812C6AA07A007EB227 /* HighlighterExtensionAliases.swift in Sources */,
|
D73E5F812C6AA07A007EB227 /* HighlighterExtensionAliases.swift in Sources */,
|
||||||
|
5C8F97392EB4616D009399B1 /* LiveStreamTimeline.swift in Sources */,
|
||||||
D73E5EC02C6A97F4007EB227 /* NostrEvent+.swift in Sources */,
|
D73E5EC02C6A97F4007EB227 /* NostrEvent+.swift in Sources */,
|
||||||
D73E5EC12C6A97F4007EB227 /* NIP98AuthenticatedRequest.swift in Sources */,
|
D73E5EC12C6A97F4007EB227 /* NIP98AuthenticatedRequest.swift in Sources */,
|
||||||
D73E5EC22C6A97F4007EB227 /* NostrAuth.swift in Sources */,
|
D73E5EC22C6A97F4007EB227 /* NostrAuth.swift in Sources */,
|
||||||
@@ -6899,6 +7103,7 @@
|
|||||||
D73E5EDF2C6A97F4007EB227 /* KeySettingsView.swift in Sources */,
|
D73E5EDF2C6A97F4007EB227 /* KeySettingsView.swift in Sources */,
|
||||||
5C0567562C8B60E60073F23A /* OffsetExtension.swift in Sources */,
|
5C0567562C8B60E60073F23A /* OffsetExtension.swift in Sources */,
|
||||||
D73E5EE02C6A97F4007EB227 /* ZapSettingsView.swift in Sources */,
|
D73E5EE02C6A97F4007EB227 /* ZapSettingsView.swift in Sources */,
|
||||||
|
5C8F97142EB45FAA009399B1 /* LiveChatTimeline.swift in Sources */,
|
||||||
D73E5F792C6A9C4C007EB227 /* HomeModel.swift in Sources */,
|
D73E5F792C6A9C4C007EB227 /* HomeModel.swift in Sources */,
|
||||||
D73E5EE12C6A97F4007EB227 /* TranslationSettingsView.swift in Sources */,
|
D73E5EE12C6A97F4007EB227 /* TranslationSettingsView.swift in Sources */,
|
||||||
D73E5EE22C6A97F4007EB227 /* SearchSettingsView.swift in Sources */,
|
D73E5EE22C6A97F4007EB227 /* SearchSettingsView.swift in Sources */,
|
||||||
@@ -6921,6 +7126,7 @@
|
|||||||
D73E5EF32C6A97F4007EB227 /* DamusPurpleVerifyNpubView.swift in Sources */,
|
D73E5EF32C6A97F4007EB227 /* DamusPurpleVerifyNpubView.swift in Sources */,
|
||||||
D73E5EF42C6A97F4007EB227 /* DamusPurpleAccountView.swift in Sources */,
|
D73E5EF42C6A97F4007EB227 /* DamusPurpleAccountView.swift in Sources */,
|
||||||
5CB0172E2D42C76A00A9ED05 /* BalanceView.swift in Sources */,
|
5CB0172E2D42C76A00A9ED05 /* BalanceView.swift in Sources */,
|
||||||
|
5C8F973D2EB46197009399B1 /* LiveStreamPreview.swift in Sources */,
|
||||||
D73E5EF52C6A97F4007EB227 /* DamusPurpleNewUserOnboardingView.swift in Sources */,
|
D73E5EF52C6A97F4007EB227 /* DamusPurpleNewUserOnboardingView.swift in Sources */,
|
||||||
D73E5EF62C6A97F4007EB227 /* SearchingEventView.swift in Sources */,
|
D73E5EF62C6A97F4007EB227 /* SearchingEventView.swift in Sources */,
|
||||||
D73E5EF72C6A97F4007EB227 /* PullDownSearch.swift in Sources */,
|
D73E5EF72C6A97F4007EB227 /* PullDownSearch.swift in Sources */,
|
||||||
@@ -6929,6 +7135,7 @@
|
|||||||
D73B74E32D8365BA0067BDBC /* ExtraFonts.swift in Sources */,
|
D73B74E32D8365BA0067BDBC /* ExtraFonts.swift in Sources */,
|
||||||
D73E5EF92C6A97F4007EB227 /* EventGroupView.swift in Sources */,
|
D73E5EF92C6A97F4007EB227 /* EventGroupView.swift in Sources */,
|
||||||
D73E5EFA2C6A97F4007EB227 /* NotificationItemView.swift in Sources */,
|
D73E5EFA2C6A97F4007EB227 /* NotificationItemView.swift in Sources */,
|
||||||
|
5C8F97272EB460CA009399B1 /* LiveStreamBanner.swift in Sources */,
|
||||||
D73E5EFB2C6A97F4007EB227 /* ProfilePicturesView.swift in Sources */,
|
D73E5EFB2C6A97F4007EB227 /* ProfilePicturesView.swift in Sources */,
|
||||||
D73E5EFC2C6A97F4007EB227 /* DamusAppNotificationView.swift in Sources */,
|
D73E5EFC2C6A97F4007EB227 /* DamusAppNotificationView.swift in Sources */,
|
||||||
D73E5EFD2C6A97F4007EB227 /* InnerTimelineView.swift in Sources */,
|
D73E5EFD2C6A97F4007EB227 /* InnerTimelineView.swift in Sources */,
|
||||||
@@ -6996,6 +7203,7 @@
|
|||||||
D73E5F312C6A97F4007EB227 /* EventMenu.swift in Sources */,
|
D73E5F312C6A97F4007EB227 /* EventMenu.swift in Sources */,
|
||||||
D73E5F322C6A97F4007EB227 /* EventMutingContainerView.swift in Sources */,
|
D73E5F322C6A97F4007EB227 /* EventMutingContainerView.swift in Sources */,
|
||||||
D73E5F332C6A97F4007EB227 /* ZapEvent.swift in Sources */,
|
D73E5F332C6A97F4007EB227 /* ZapEvent.swift in Sources */,
|
||||||
|
5C8F97362EB46145009399B1 /* LiveStreamView.swift in Sources */,
|
||||||
D73E5F342C6A97F4007EB227 /* TextEvent.swift in Sources */,
|
D73E5F342C6A97F4007EB227 /* TextEvent.swift in Sources */,
|
||||||
D73E5F352C6A97F4007EB227 /* WideEventView.swift in Sources */,
|
D73E5F352C6A97F4007EB227 /* WideEventView.swift in Sources */,
|
||||||
D7D68FF92C9E01BE0015A515 /* KFClickable.swift in Sources */,
|
D7D68FF92C9E01BE0015A515 /* KFClickable.swift in Sources */,
|
||||||
@@ -7011,13 +7219,17 @@
|
|||||||
D73E5F3D2C6A97F4007EB227 /* QuoteRepostsView.swift in Sources */,
|
D73E5F3D2C6A97F4007EB227 /* QuoteRepostsView.swift in Sources */,
|
||||||
D73E5F3E2C6A97F4007EB227 /* ReactionView.swift in Sources */,
|
D73E5F3E2C6A97F4007EB227 /* ReactionView.swift in Sources */,
|
||||||
D73E5F3F2C6A97F4007EB227 /* EventActionBar.swift in Sources */,
|
D73E5F3F2C6A97F4007EB227 /* EventActionBar.swift in Sources */,
|
||||||
|
5C8F97452EB461DB009399B1 /* EventTags.swift in Sources */,
|
||||||
D73E5F402C6A97F5007EB227 /* EventDetailBar.swift in Sources */,
|
D73E5F402C6A97F5007EB227 /* EventDetailBar.swift in Sources */,
|
||||||
|
5C8F972E2EB46116009399B1 /* LiveStreamStatus.swift in Sources */,
|
||||||
D73E5F412C6A97F5007EB227 /* ShareAction.swift in Sources */,
|
D73E5F412C6A97F5007EB227 /* ShareAction.swift in Sources */,
|
||||||
D73E5F422C6A97F5007EB227 /* RepostAction.swift in Sources */,
|
D73E5F422C6A97F5007EB227 /* RepostAction.swift in Sources */,
|
||||||
D73E5F942C6AA74D007EB227 /* EULAView.swift in Sources */,
|
D73E5F942C6AA74D007EB227 /* EULAView.swift in Sources */,
|
||||||
D73E5F432C6A97F5007EB227 /* ShareActionButton.swift in Sources */,
|
D73E5F432C6A97F5007EB227 /* ShareActionButton.swift in Sources */,
|
||||||
D73E5F442C6A97F5007EB227 /* BigButton.swift in Sources */,
|
D73E5F442C6A97F5007EB227 /* BigButton.swift in Sources */,
|
||||||
D73E5F8D2C6AA6D7007EB227 /* AddMuteItemView.swift in Sources */,
|
D73E5F8D2C6AA6D7007EB227 /* AddMuteItemView.swift in Sources */,
|
||||||
|
5C8F970F2EB45F7C009399B1 /* LiveChatHomeView.swift in Sources */,
|
||||||
|
5C8F97412EB461B2009399B1 /* LiveStreamHomeView.swift in Sources */,
|
||||||
D73E5F452C6A97F5007EB227 /* AddRelayView.swift in Sources */,
|
D73E5F452C6A97F5007EB227 /* AddRelayView.swift in Sources */,
|
||||||
D73E5F472C6A97F5007EB227 /* BookmarksView.swift in Sources */,
|
D73E5F472C6A97F5007EB227 /* BookmarksView.swift in Sources */,
|
||||||
D73E5F482C6A97F5007EB227 /* CarouselView.swift in Sources */,
|
D73E5F482C6A97F5007EB227 /* CarouselView.swift in Sources */,
|
||||||
@@ -7087,6 +7299,7 @@
|
|||||||
D703D7762C670BCA00A400EA /* Verifier.swift in Sources */,
|
D703D7762C670BCA00A400EA /* Verifier.swift in Sources */,
|
||||||
D703D75A2C670A7900A400EA /* LNUrls.swift in Sources */,
|
D703D75A2C670A7900A400EA /* LNUrls.swift in Sources */,
|
||||||
D703D74B2C6709C900A400EA /* NoteId.swift in Sources */,
|
D703D74B2C6709C900A400EA /* NoteId.swift in Sources */,
|
||||||
|
5C8F97162EB45FD7009399B1 /* LiveChatView.swift in Sources */,
|
||||||
D703D7B52C67111C00A400EA /* CollectionExtension.swift in Sources */,
|
D703D7B52C67111C00A400EA /* CollectionExtension.swift in Sources */,
|
||||||
D703D7722C670B8000A400EA /* FlatBufferBuilder.swift in Sources */,
|
D703D7722C670B8000A400EA /* FlatBufferBuilder.swift in Sources */,
|
||||||
D703D7502C6709F500A400EA /* NdbTxn.swift in Sources */,
|
D703D7502C6709F500A400EA /* NdbTxn.swift in Sources */,
|
||||||
@@ -7115,6 +7328,7 @@
|
|||||||
D703D7692C670B2600A400EA /* Block.swift in Sources */,
|
D703D7692C670B2600A400EA /* Block.swift in Sources */,
|
||||||
D703D77D2C670C0300A400EA /* FlatbuffersErrors.swift in Sources */,
|
D703D77D2C670C0300A400EA /* FlatbuffersErrors.swift in Sources */,
|
||||||
D703D7A62C670E5200A400EA /* builder.c in Sources */,
|
D703D7A62C670E5200A400EA /* builder.c in Sources */,
|
||||||
|
5C8F974B2EB4620A009399B1 /* Glow.swift in Sources */,
|
||||||
D703D78D2C670CAF00A400EA /* UpdateStatsNotify.swift in Sources */,
|
D703D78D2C670CAF00A400EA /* UpdateStatsNotify.swift in Sources */,
|
||||||
D703D75C2C670A8400A400EA /* NdbNote.swift in Sources */,
|
D703D75C2C670A8400A400EA /* NdbNote.swift in Sources */,
|
||||||
D703D7592C670A7300A400EA /* Profiles.swift in Sources */,
|
D703D7592C670A7300A400EA /* Profiles.swift in Sources */,
|
||||||
@@ -7151,8 +7365,9 @@
|
|||||||
D7E5B2D32EA0188200CF47AC /* StreamPipelineDiagnostics.swift in Sources */,
|
D7E5B2D32EA0188200CF47AC /* StreamPipelineDiagnostics.swift in Sources */,
|
||||||
D73E5E162C6A9619007EB227 /* PostView.swift in Sources */,
|
D73E5E162C6A9619007EB227 /* PostView.swift in Sources */,
|
||||||
D703D7872C670C7E00A400EA /* DamusPurpleEnvironment.swift in Sources */,
|
D703D7872C670C7E00A400EA /* DamusPurpleEnvironment.swift in Sources */,
|
||||||
|
5C8F970C2EB45E8C009399B1 /* LiveChatModel.swift in Sources */,
|
||||||
D703D7892C670C8600A400EA /* DeepLPlan.swift in Sources */,
|
D703D7892C670C8600A400EA /* DeepLPlan.swift in Sources */,
|
||||||
5CB645AA2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
|
5CB645AA2EAC01430018BD91 /* DamusLabsExperiments.swift in Sources */,
|
||||||
D73E5E182C6A963D007EB227 /* AttachMediaUtility.swift in Sources */,
|
D73E5E182C6A963D007EB227 /* AttachMediaUtility.swift in Sources */,
|
||||||
D73E5F852C6AA628007EB227 /* LoadScript.swift in Sources */,
|
D73E5F852C6AA628007EB227 /* LoadScript.swift in Sources */,
|
||||||
D703D74E2C6709DA00A400EA /* Pubkey.swift in Sources */,
|
D703D74E2C6709DA00A400EA /* Pubkey.swift in Sources */,
|
||||||
@@ -7177,6 +7392,7 @@
|
|||||||
D703D71E2C66E47100A400EA /* ActionViewController.swift in Sources */,
|
D703D71E2C66E47100A400EA /* ActionViewController.swift in Sources */,
|
||||||
D703D7472C67092700A400EA /* UserSettingsStore.swift in Sources */,
|
D703D7472C67092700A400EA /* UserSettingsStore.swift in Sources */,
|
||||||
D703D7852C670C6100A400EA /* Notify.swift in Sources */,
|
D703D7852C670C6100A400EA /* Notify.swift in Sources */,
|
||||||
|
5C8F97312EB46126009399B1 /* LiveStreamViewers.swift in Sources */,
|
||||||
D703D7532C670A2600A400EA /* Wallet.swift in Sources */,
|
D703D7532C670A2600A400EA /* Wallet.swift in Sources */,
|
||||||
D755B28F2D3E7D8800BBEEFA /* NIP37Draft.swift in Sources */,
|
D755B28F2D3E7D8800BBEEFA /* NIP37Draft.swift in Sources */,
|
||||||
D703D75F2C670AA200A400EA /* NostrEvent.swift in Sources */,
|
D703D75F2C670AA200A400EA /* NostrEvent.swift in Sources */,
|
||||||
|
|||||||
@@ -512,6 +512,15 @@ func make_like_event(keypair: FullKeypair, liked: NostrEvent, content: String =
|
|||||||
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 7, tags: tags)
|
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 7, tags: tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func make_live_chat_event(keypair: FullKeypair, content: String, root: String, dtag: String, relayURL: RelayURL?) -> NostrEvent? {
|
||||||
|
//var tags = Array(boosted.referenced_pubkeys).map({ pk in pk.tag })
|
||||||
|
var aTagBuilder = ["a", "30311:\(root):\(dtag)"]
|
||||||
|
|
||||||
|
var tags: [[String]] = [aTagBuilder]
|
||||||
|
|
||||||
|
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 1311, tags: tags)
|
||||||
|
}
|
||||||
|
|
||||||
func generate_private_keypair(our_privkey: Privkey, id: NoteId, created_at: UInt32) -> FullKeypair? {
|
func generate_private_keypair(our_privkey: Privkey, id: NoteId, created_at: UInt32) -> FullKeypair? {
|
||||||
let to_hash = our_privkey.hex() + id.hex() + String(created_at)
|
let to_hash = our_privkey.hex() + id.hex() + String(created_at)
|
||||||
guard let dat = to_hash.data(using: .utf8) else {
|
guard let dat = to_hash.data(using: .utf8) else {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ enum NostrKind: UInt32, Codable {
|
|||||||
case boost = 6
|
case boost = 6
|
||||||
case like = 7
|
case like = 7
|
||||||
case chat = 42
|
case chat = 42
|
||||||
|
case live_chat = 1311
|
||||||
case mute_list = 10000
|
case mute_list = 10000
|
||||||
case relay_list = 10002
|
case relay_list = 10002
|
||||||
case interest_list = 10015
|
case interest_list = 10015
|
||||||
@@ -30,6 +31,7 @@ enum NostrKind: UInt32, Codable {
|
|||||||
case nwc_request = 23194
|
case nwc_request = 23194
|
||||||
case nwc_response = 23195
|
case nwc_response = 23195
|
||||||
case http_auth = 27235
|
case http_auth = 27235
|
||||||
|
case live = 30311
|
||||||
case status = 30315
|
case status = 30315
|
||||||
case contact_card = 30_382
|
case contact_card = 30_382
|
||||||
case follow_list = 39089
|
case follow_list = 39089
|
||||||
|
|||||||
@@ -13,26 +13,32 @@ struct EventTop: View {
|
|||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
let pubkey: Pubkey
|
let pubkey: Pubkey
|
||||||
let is_anon: Bool
|
let is_anon: Bool
|
||||||
|
let size: EventViewKind
|
||||||
|
let options: EventViewOptions
|
||||||
|
|
||||||
init(state: DamusState, event: NostrEvent, pubkey: Pubkey, is_anon: Bool) {
|
init(state: DamusState, event: NostrEvent, pubkey: Pubkey, is_anon: Bool, size: EventViewKind, options: EventViewOptions) {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.event = event
|
self.event = event
|
||||||
self.pubkey = pubkey
|
self.pubkey = pubkey
|
||||||
self.is_anon = is_anon
|
self.is_anon = is_anon
|
||||||
|
self.size = size
|
||||||
|
self.options = options
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProfileName(is_anon: Bool) -> some View {
|
func ProfileName(is_anon: Bool) -> some View {
|
||||||
let pk = is_anon ? ANON_PUBKEY : self.pubkey
|
let pk = is_anon ? ANON_PUBKEY : self.pubkey
|
||||||
return EventProfileName(pubkey: pk, damus: state, size: .normal)
|
return EventProfileName(pubkey: pk, damus: state, size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 0) {
|
HStack(alignment: .center, spacing: 0) {
|
||||||
ProfileName(is_anon: is_anon)
|
ProfileName(is_anon: is_anon)
|
||||||
TimeDot()
|
TimeDot()
|
||||||
RelativeTime(time: state.events.get_cache_data(event.id).relative_time)
|
RelativeTime(time: state.events.get_cache_data(event.id).relative_time, size: size, font_size: state.settings.font_size)
|
||||||
Spacer()
|
Spacer()
|
||||||
EventMenuContext(damus: state, event: event)
|
if !options.contains(.no_context_menu) {
|
||||||
|
EventMenuContext(damus: state, event: event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
}
|
}
|
||||||
@@ -40,6 +46,6 @@ struct EventTop: View {
|
|||||||
|
|
||||||
struct EventTop_Previews: PreviewProvider {
|
struct EventTop_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
EventTop(state: test_damus_state, event: test_note, pubkey: test_note.pubkey, is_anon: false)
|
EventTop(state: test_damus_state, event: test_note, pubkey: test_note.pubkey, is_anon: false, size: .normal, options: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import SwiftUI
|
|||||||
|
|
||||||
struct RelativeTime: View {
|
struct RelativeTime: View {
|
||||||
@ObservedObject var time: RelativeTimeModel
|
@ObservedObject var time: RelativeTimeModel
|
||||||
|
let size: EventViewKind
|
||||||
|
let font_size: Double
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(verbatim: "\(time.value)")
|
Text(verbatim: "\(time.value)")
|
||||||
.font(.system(size: 16))
|
.font(eventviewsize_to_font(size, font_size: font_size))
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,6 +22,6 @@ struct RelativeTime: View {
|
|||||||
|
|
||||||
struct RelativeTime_Previews: PreviewProvider {
|
struct RelativeTime_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
RelativeTime(time: RelativeTimeModel())
|
RelativeTime(time: RelativeTimeModel(), size: .normal, font_size: 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,9 +63,11 @@ struct EventShell<Content: View>: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon)
|
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon, size: options.contains(.small_text) ? .small : .normal, options: options)
|
||||||
|
|
||||||
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
if !options.contains(.no_status) {
|
||||||
|
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
||||||
|
}
|
||||||
|
|
||||||
if !options.contains(.no_replying_to) {
|
if !options.contains(.no_replying_to) {
|
||||||
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
||||||
@@ -93,7 +95,7 @@ struct EventShell<Content: View>: View {
|
|||||||
Pfp(is_anon: is_anon)
|
Pfp(is_anon: is_anon)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon)
|
EventTop(state: state, event: event, pubkey: pubkey, is_anon: is_anon, size: options.contains(.small_text) ? .small : .normal, options: options)
|
||||||
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
UserStatusView(status: state.profiles.profile_data(pubkey).status, show_general: state.settings.show_general_statuses, show_music: state.settings.show_music_statuses)
|
||||||
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
ReplyPart(events: state.events, event: event, keypair: state.keypair, ndb: state.ndb)
|
||||||
ProxyView(event: event)
|
ProxyView(event: event)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class LoadableNostrEventViewModel: ObservableObject {
|
|||||||
case .zap, .zap_request:
|
case .zap, .zap_request:
|
||||||
guard let zap = await get_zap(from: ev, state: damus_state) else { return .not_found }
|
guard let zap = await get_zap(from: ev, state: damus_state) else { return .not_found }
|
||||||
return .loaded(route: Route.Zaps(target: zap.target))
|
return .loaded(route: Route.Zaps(target: zap.target))
|
||||||
case .contacts, .metadata, .delete, .boost, .chat, .mute_list, .list_deprecated, .draft, .longform, .nwc_request, .nwc_response, .http_auth, .status, .relay_list, .follow_list, .interest_list, .contact_card:
|
case .contacts, .metadata, .delete, .boost, .chat, .mute_list, .list_deprecated, .draft, .longform, .nwc_request, .nwc_response, .http_auth, .status, .relay_list, .follow_list, .interest_list, .contact_card, .live, .live_chat:
|
||||||
return .unknown_or_unsupported_kind
|
return .unknown_or_unsupported_kind
|
||||||
}
|
}
|
||||||
case .naddr(let naddr):
|
case .naddr(let naddr):
|
||||||
|
|||||||
@@ -23,9 +23,13 @@ struct EventViewOptions: OptionSet {
|
|||||||
static let truncate_content_very_short = EventViewOptions(rawValue: 1 << 11)
|
static let truncate_content_very_short = EventViewOptions(rawValue: 1 << 11)
|
||||||
static let no_previews = EventViewOptions(rawValue: 1 << 12)
|
static let no_previews = EventViewOptions(rawValue: 1 << 12)
|
||||||
static let no_show_more = EventViewOptions(rawValue: 1 << 13)
|
static let no_show_more = EventViewOptions(rawValue: 1 << 13)
|
||||||
|
static let small_text = EventViewOptions(rawValue: 1 << 14)
|
||||||
|
static let no_status = EventViewOptions(rawValue: 1 << 15)
|
||||||
|
static let no_context_menu = EventViewOptions(rawValue: 1 << 16)
|
||||||
|
|
||||||
static let embedded: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested]
|
static let embedded: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested]
|
||||||
static let embedded_text_only: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested, .no_media, .truncate_content_very_short, .no_previews]
|
static let embedded_text_only: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested, .no_media, .truncate_content_very_short, .no_previews]
|
||||||
|
static let live_chat: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .no_previews, .nested, .small_text, .no_status, .no_context_menu]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TextEvent: View {
|
struct TextEvent: View {
|
||||||
@@ -51,6 +55,16 @@ struct TextEvent: View {
|
|||||||
|
|
||||||
func EvBody(options: EventViewOptions) -> some View {
|
func EvBody(options: EventViewOptions) -> some View {
|
||||||
let blur_imgs = should_blur_images(settings: damus.settings, contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
|
let blur_imgs = should_blur_images(settings: damus.settings, contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
|
||||||
|
|
||||||
|
if options.contains(.small_text) {
|
||||||
|
return NoteContentView(
|
||||||
|
damus_state: damus,
|
||||||
|
event: event,
|
||||||
|
blur_images: blur_imgs,
|
||||||
|
size: .small,
|
||||||
|
options: options)
|
||||||
|
}
|
||||||
|
|
||||||
return NoteContentView(
|
return NoteContentView(
|
||||||
damus_state: damus,
|
damus_state: damus,
|
||||||
event: event,
|
event: event,
|
||||||
|
|||||||
43
damus/Features/Labs/Views/Components/LabsExplainerView.swift
Normal file
43
damus/Features/Labs/Views/Components/LabsExplainerView.swift
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// LabsExplainerView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 11/6/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LabsExplainerView: View {
|
||||||
|
let labName: String
|
||||||
|
let systemImage: String
|
||||||
|
let labDescription: String
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
PurpleBackdrop {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: systemImage)
|
||||||
|
.resizable()
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: 25, height: 25)
|
||||||
|
Text(labName)
|
||||||
|
.font(.title)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(NSLocalizedString(labDescription, comment: "Description of the feature."))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
.overlay(Rectangle().frame(width: nil, height: 1, alignment: .top).foregroundColor(DamusColors.purple), alignment: .top)
|
||||||
|
.presentationDragIndicator(.visible)
|
||||||
|
.presentationDetents([.height(300)])
|
||||||
|
}
|
||||||
|
}
|
||||||
40
damus/Features/Labs/Views/Components/LabsToggleView.swift
Normal file
40
damus/Features/Labs/Views/Components/LabsToggleView.swift
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// LabsToggleView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 11/6/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LabsToggleView: View {
|
||||||
|
let toggleName: String
|
||||||
|
let systemImage: String
|
||||||
|
@Binding var isOn: Bool
|
||||||
|
@Binding var showInfo: Bool
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
HStack {
|
||||||
|
Toggle(toggleName, systemImage: systemImage, isOn: $isOn)
|
||||||
|
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||||
|
.font(.title2)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
}
|
||||||
|
.padding(15)
|
||||||
|
.background(DamusColors.black)
|
||||||
|
.cornerRadius(20)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 20)
|
||||||
|
.stroke(isOn ? DamusColors.purple : DamusColors.neutral6, lineWidth: 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
Image("info")
|
||||||
|
.foregroundColor(DamusColors.purple)
|
||||||
|
.onTapGesture {
|
||||||
|
showInfo.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ struct DamusLabsView: View {
|
|||||||
PurpleBackdrop {
|
PurpleBackdrop {
|
||||||
VStack {
|
VStack {
|
||||||
MainContent
|
MainContent
|
||||||
.padding(.top, 125)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
@@ -51,15 +50,13 @@ struct DamusLabsView: View {
|
|||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
VStack {
|
VStack {
|
||||||
LabsLogoView()
|
|
||||||
|
|
||||||
if let purple_account, purple_account.active == true {
|
if let purple_account, purple_account.active == true {
|
||||||
DamusLabsExpirements(damus_state: damus_state)
|
DamusLabsExperiments(damus_state: damus_state, settings: damus_state.settings)
|
||||||
} else {
|
} else {
|
||||||
|
LabsLogoView()
|
||||||
|
.padding(.top, 125)
|
||||||
LabsIntroductionView(damus_state: damus_state)
|
LabsIntroductionView(damus_state: damus_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
damus/Features/Labs/Views/DamusLabsExperiments.swift
Normal file
67
damus/Features/Labs/Views/DamusLabsExperiments.swift
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// DamusLabsExpirements.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 10/24/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct DamusLabsExperiments: View {
|
||||||
|
|
||||||
|
let damus_state: DamusState
|
||||||
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
@State var show_live_explainer: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView {
|
||||||
|
|
||||||
|
LabsLogoView()
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 30) {
|
||||||
|
PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("As a subscriber, you’re getting an early look at new and innovative tools. These are beta features — still being tested and tuned. Try them out, share your thoughts, and help us perfect what’s next.", comment: "Damus Labs explainer"))
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Text(NSLocalizedString("More features coming soon!", comment: ""))
|
||||||
|
.font(.title2)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.padding(.bottom, 2)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(15)
|
||||||
|
.background(DamusColors.black)
|
||||||
|
.cornerRadius(15)
|
||||||
|
.padding(.top, 10)
|
||||||
|
|
||||||
|
LabsToggleView(toggleName: "Live", systemImage: "record.circle", isOn: $settings.live, showInfo: $show_live_explainer)
|
||||||
|
|
||||||
|
}
|
||||||
|
.padding([.trailing, .leading], 20)
|
||||||
|
.padding(.bottom, 50)
|
||||||
|
|
||||||
|
Image("damooseLabs")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
|
||||||
|
}
|
||||||
|
.ignoresSafeArea(edges: .bottom)
|
||||||
|
.sheet(isPresented: $show_live_explainer) {
|
||||||
|
LabsExplainerView(
|
||||||
|
labName: "Live",
|
||||||
|
systemImage: "record.circle",
|
||||||
|
labDescription: "This will allow you to see all the real-time live streams happening on Nostr! As well as let you view and interact in the Live Chat. Please keep in mind this is still a work in progress and issues are expected. When enabled you will see the Live option in your side menu.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
PurpleBackdrop {
|
||||||
|
DamusLabsExperiments(damus_state: test_damus_state, settings: test_damus_state.settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
//
|
|
||||||
// DamusLabsExpirements.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by eric on 10/24/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
|
|
||||||
struct DamusLabsExpirements: View {
|
|
||||||
|
|
||||||
let damus_state: DamusState
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack {
|
|
||||||
VStack(alignment: .leading, spacing: 30) {
|
|
||||||
PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("As a subscriber, you’re getting an early look at new and innovative tools. These are beta features — still being tested and tuned. Try them out, share your thoughts, and help us perfect what’s next.", comment: "Damus Labs explainer"))
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
|
|
||||||
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Text("Features coming soon!")
|
|
||||||
.font(.title2)
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.fontWeight(.bold)
|
|
||||||
.padding(.bottom, 2)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.padding(15)
|
|
||||||
.background(DamusColors.neutral6)
|
|
||||||
.cornerRadius(15)
|
|
||||||
.padding(.top, 10)
|
|
||||||
|
|
||||||
}
|
|
||||||
.padding([.trailing, .leading], 30)
|
|
||||||
.padding(.bottom, 20)
|
|
||||||
|
|
||||||
Image("damooseLabs")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
PurpleBackdrop {
|
|
||||||
DamusLabsExpirements(damus_state: test_damus_state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
99
damus/Features/Live/LiveChat/Models/LiveChatModel.swift
Normal file
99
damus/Features/Live/LiveChat/Models/LiveChatModel.swift
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
//
|
||||||
|
// LiveChatModel.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/7/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// The data model for the LiveEventHome view
|
||||||
|
class LiveChatModel: ObservableObject {
|
||||||
|
var events: EventHolder
|
||||||
|
@Published var loading: Bool = false
|
||||||
|
|
||||||
|
let damus_state: DamusState
|
||||||
|
let root: String
|
||||||
|
let dtag: String
|
||||||
|
var subscriptionTask: Task<Void, any Error>? = nil
|
||||||
|
let limit: UInt32 = 1000
|
||||||
|
|
||||||
|
init(damus_state: DamusState, root: String, dtag: String) {
|
||||||
|
self.damus_state = damus_state
|
||||||
|
self.root = root
|
||||||
|
self.dtag = dtag
|
||||||
|
self.events = EventHolder(on_queue: { ev in
|
||||||
|
preload_events(state: damus_state, events: [ev])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func filter_muted() {
|
||||||
|
events.filter { should_show_event(state: damus_state, ev: $0) }
|
||||||
|
self.objectWillChange.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func set(loading: Bool) {
|
||||||
|
self.loading = loading
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribe() {
|
||||||
|
subscriptionTask?.cancel()
|
||||||
|
|
||||||
|
subscriptionTask = Task {
|
||||||
|
await set(loading: true)
|
||||||
|
|
||||||
|
let live_chat_filter = NostrFilter(kinds: [.live_chat])
|
||||||
|
|
||||||
|
let to_relays = await damus_state.nostrNetwork.ourRelayDescriptors
|
||||||
|
.map { $0.url }
|
||||||
|
.filter { !damus_state.relay_filters.is_filtered(timeline: .search, relay_id: $0) }
|
||||||
|
|
||||||
|
for await item in damus_state.nostrNetwork.reader.advancedStream(filters: [live_chat_filter], to: to_relays) {
|
||||||
|
switch item {
|
||||||
|
case .event(let lender):
|
||||||
|
await lender.justUseACopy({ await handle_event(event: $0) })
|
||||||
|
case .eose:
|
||||||
|
continue
|
||||||
|
case .ndbEose:
|
||||||
|
await set(loading: false)
|
||||||
|
case .networkEose:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func unsubscribe(to: RelayURL? = nil) {
|
||||||
|
set(loading: false)
|
||||||
|
subscriptionTask?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(event: NostrEvent) async {
|
||||||
|
for tag in event.tags {
|
||||||
|
guard tag.count >= 2 else { continue }
|
||||||
|
switch tag[0].string() {
|
||||||
|
case "a":
|
||||||
|
let atag = tag[1].string()
|
||||||
|
let split = atag.split(separator: ":")
|
||||||
|
if root != split[1] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if dtag != split[2] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await MainActor.run {
|
||||||
|
if should_show_event(state: damus_state, ev: event) {
|
||||||
|
if self.events.insert(event) {
|
||||||
|
self.objectWillChange.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
136
damus/Features/Live/LiveChat/Views/LiveChatHomeView.swift
Normal file
136
damus/Features/Live/LiveChat/Views/LiveChatHomeView.swift
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
//
|
||||||
|
// LiveChatHomeView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/7/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveChatHomeView: View, KeyboardReadable {
|
||||||
|
let state: DamusState
|
||||||
|
let event: LiveEvent
|
||||||
|
@StateObject var model: LiveChatModel
|
||||||
|
@State private var chat_message = ""
|
||||||
|
@FocusState private var isTextFieldFocused: Bool
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
func content_filter(_ fstate: FilterState) -> ((NostrEvent) -> Bool) {
|
||||||
|
var filters = ContentFilters.defaults(damus_state: state)
|
||||||
|
filters.append(fstate.filter)
|
||||||
|
return ContentFilters(filters: filters).filter
|
||||||
|
}
|
||||||
|
|
||||||
|
var Footer: some View {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
ChatInput
|
||||||
|
|
||||||
|
Button(
|
||||||
|
role: .none,
|
||||||
|
action: {
|
||||||
|
Task { await send_chat() }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Label("", image: "send")
|
||||||
|
.font(.title)
|
||||||
|
}
|
||||||
|
.disabled(chat_message.isEmpty)
|
||||||
|
}
|
||||||
|
.safeAreaInset(edge: .bottom) {
|
||||||
|
Color.clear.frame(height: 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func send_chat() async {
|
||||||
|
guard
|
||||||
|
let keypair = state.keypair.to_full(),
|
||||||
|
let liveChat = make_live_chat_event(keypair: keypair, content: chat_message, root: event.event.pubkey.hex(), dtag: event.uuid ?? "", relayURL: nil)
|
||||||
|
else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await state.nostrNetwork.postbox.send(liveChat)
|
||||||
|
chat_message = ""
|
||||||
|
end_editing()
|
||||||
|
}
|
||||||
|
|
||||||
|
var ChatInput: some View {
|
||||||
|
HStack{
|
||||||
|
TextField(NSLocalizedString("Chat", comment: "Placeholder text to prompt entry of chat message."), text: $chat_message)
|
||||||
|
.autocorrectionDisabled(true)
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
|
.focused($isTextFieldFocused)
|
||||||
|
}
|
||||||
|
.padding(10)
|
||||||
|
.background(.secondary.opacity(0.2))
|
||||||
|
.cornerRadius(20)
|
||||||
|
.padding(.horizontal, 15)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scroll_to_end(_ scroller: ScrollViewProxy, animated: Bool = false) {
|
||||||
|
if animated {
|
||||||
|
withAnimation {
|
||||||
|
scroller.scrollTo("endblock")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scroller.scrollTo("endblock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Chat: some View {
|
||||||
|
ScrollViewReader { scroller in
|
||||||
|
ScrollView {
|
||||||
|
LazyVStack(alignment: .leading, spacing: 0) {
|
||||||
|
let events = model.events.events
|
||||||
|
ForEach(Array(zip(events, events.indices).reversed()).filter { should_show_event(state: state, ev: $0.0)}, id: \.0.id) { (ev, ind) in
|
||||||
|
TextEvent(damus: state, event: ev, pubkey: ev.pubkey, options: .live_chat)
|
||||||
|
}
|
||||||
|
EndBlock(height: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dismissKeyboardOnTap()
|
||||||
|
.onAppear {
|
||||||
|
scroll_to_end(scroller)
|
||||||
|
}.onChange(of: model.events.events.count) { _ in
|
||||||
|
scroll_to_end(scroller, animated: true)
|
||||||
|
}
|
||||||
|
.padding(.top, 5)
|
||||||
|
|
||||||
|
Footer
|
||||||
|
.onReceive(keyboardPublisher) { visible in
|
||||||
|
guard visible else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||||
|
scroll_to_end(scroller, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
HStack {
|
||||||
|
Text("Live Chat")
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.padding(5)
|
||||||
|
|
||||||
|
LiveStreamViewers(state: state, currentParticipants: event.currentParticipants ?? 0, preview: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
Chat
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.new_mutes)) { _ in
|
||||||
|
self.model.filter_muted()
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
model.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
136
damus/Features/Live/LiveChat/Views/LiveChatTimeline.swift
Normal file
136
damus/Features/Live/LiveChat/Views/LiveChatTimeline.swift
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
//
|
||||||
|
// LiveChatTimeline.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/7/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveChatTimelineView<Content: View>: View {
|
||||||
|
@ObservedObject var events: EventHolder
|
||||||
|
@Binding var loading: Bool
|
||||||
|
|
||||||
|
let damus: DamusState
|
||||||
|
let show_friend_icon: Bool
|
||||||
|
let filter: (NostrEvent) -> Bool
|
||||||
|
let content: Content?
|
||||||
|
let apply_mute_rules: Bool
|
||||||
|
|
||||||
|
init(events: EventHolder, loading: Binding<Bool>, headerHeight: Binding<CGFloat>, headerOffset: Binding<CGFloat>, damus: DamusState, show_friend_icon: Bool, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true, content: (() -> Content)? = nil) {
|
||||||
|
self.events = events
|
||||||
|
self._loading = loading
|
||||||
|
self.damus = damus
|
||||||
|
self.show_friend_icon = show_friend_icon
|
||||||
|
self.filter = filter
|
||||||
|
self.apply_mute_rules = apply_mute_rules
|
||||||
|
self.content = content?()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(events: EventHolder, loading: Binding<Bool>, damus: DamusState, show_friend_icon: Bool, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true, content: (() -> Content)? = nil) {
|
||||||
|
self.events = events
|
||||||
|
self._loading = loading
|
||||||
|
self.damus = damus
|
||||||
|
self.show_friend_icon = show_friend_icon
|
||||||
|
self.filter = filter
|
||||||
|
self.apply_mute_rules = apply_mute_rules
|
||||||
|
self.content = content?()
|
||||||
|
}
|
||||||
|
|
||||||
|
func scroll_to_end(_ scroller: ScrollViewProxy, animated: Bool = false) {
|
||||||
|
if animated {
|
||||||
|
withAnimation {
|
||||||
|
scroller.scrollTo("endblock")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scroller.scrollTo("endblock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollViewReader { scroller in
|
||||||
|
ScrollView {
|
||||||
|
if let content {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
Color.clear
|
||||||
|
.id("startblock")
|
||||||
|
.frame(height: 0)
|
||||||
|
|
||||||
|
LiveChatInnerView(events: events, damus: damus, filter: loading ? { _ in true } : filter, apply_mute_rules: self.apply_mute_rules)
|
||||||
|
.redacted(reason: loading ? .placeholder : [])
|
||||||
|
.shimmer(loading)
|
||||||
|
.disabled(loading)
|
||||||
|
.background {
|
||||||
|
GeometryReader { proxy -> Color in
|
||||||
|
handle_scroll_queue(proxy, queue: self.events)
|
||||||
|
return Color.clear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.coordinateSpace(name: "scroll")
|
||||||
|
.onReceive(handle_notify(.scroll_to_top)) { () in
|
||||||
|
events.flush()
|
||||||
|
self.events.set_should_queue(false)
|
||||||
|
scroll_to_event(scroller: scroller, id: "startblock", delay: 0.0, animate: true, anchor: .top)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
events.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LiveChatInnerView: View {
|
||||||
|
@ObservedObject var events: EventHolder
|
||||||
|
let state: DamusState
|
||||||
|
let filter: (NostrEvent) -> Bool
|
||||||
|
|
||||||
|
init(events: EventHolder, damus: DamusState, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true) {
|
||||||
|
self.events = events
|
||||||
|
self.state = damus
|
||||||
|
self.filter = apply_mute_rules ? { filter($0) && !damus.mutelist_manager.is_event_muted($0) } : filter
|
||||||
|
}
|
||||||
|
|
||||||
|
var event_options: EventViewOptions {
|
||||||
|
if self.state.settings.truncate_timeline_text {
|
||||||
|
return [.wide, .truncate_content]
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.wide]
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
LazyVStack(spacing: 0) {
|
||||||
|
let events = self.events.events
|
||||||
|
if events.isEmpty {
|
||||||
|
EmptyTimelineView()
|
||||||
|
} else {
|
||||||
|
let evs = events.filter(filter)
|
||||||
|
let indexed = Array(zip(evs, 0...))
|
||||||
|
ForEach(indexed, id: \.0.id) { tup in
|
||||||
|
let ev = tup.0
|
||||||
|
let ind = tup.1
|
||||||
|
if ev.kind == NostrKind.live_chat.rawValue {
|
||||||
|
LiveChatView(state: state, ev: ev)
|
||||||
|
.padding(.top, 7)
|
||||||
|
.onAppear {
|
||||||
|
let to_preload =
|
||||||
|
Array([indexed[safe: ind+1]?.0,
|
||||||
|
indexed[safe: ind+2]?.0,
|
||||||
|
indexed[safe: ind+3]?.0,
|
||||||
|
indexed[safe: ind+4]?.0,
|
||||||
|
indexed[safe: ind+5]?.0
|
||||||
|
].compactMap({ $0 }))
|
||||||
|
|
||||||
|
preload_events(state: state, events: to_preload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
38
damus/Features/Live/LiveChat/Views/LiveChatView.swift
Normal file
38
damus/Features/Live/LiveChat/Views/LiveChatView.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// LiveChatView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/7/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct LiveChatView: View {
|
||||||
|
let state: DamusState
|
||||||
|
let event: NostrEvent
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
@ObservedObject var artifacts: NoteArtifactsModel
|
||||||
|
|
||||||
|
init(state: DamusState, ev: NostrEvent) {
|
||||||
|
self.state = state
|
||||||
|
self.event = ev
|
||||||
|
|
||||||
|
self._artifacts = ObservedObject(wrappedValue: state.events.get_cache_data(ev.id).artifacts_model)
|
||||||
|
}
|
||||||
|
|
||||||
|
func content_filter(_ pubkeys: [Pubkey]) -> ((NostrEvent) -> Bool) {
|
||||||
|
var filters = ContentFilters.defaults(damus_state: self.state)
|
||||||
|
filters.append({ pubkeys.contains($0.pubkey) })
|
||||||
|
return ContentFilters(filters: filters).filter
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
TextEvent(damus: state, event: event, pubkey: event.pubkey, options: [.no_action_bar,.small_pfp,.wide,.no_previews,.small_text])
|
||||||
|
}
|
||||||
|
.padding(.bottom, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
71
damus/Features/Live/LiveStream/Models/LiveEvent.swift
Normal file
71
damus/Features/Live/LiveStream/Models/LiveEvent.swift
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// LiveEvent.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/10/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum LiveEventStatus: String {
|
||||||
|
case planned = "SCHEDULED"
|
||||||
|
case live = "LIVE"
|
||||||
|
case ended = "ENDED"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LiveEvent: Hashable {
|
||||||
|
let event: NostrEvent
|
||||||
|
var uuid: String? = nil
|
||||||
|
var title: String? = nil
|
||||||
|
var summary: String? = nil
|
||||||
|
var image: URL? = nil
|
||||||
|
var streaming: URL? = nil
|
||||||
|
var recording: URL? = nil
|
||||||
|
var starts: String? = nil
|
||||||
|
var ends: String? = nil
|
||||||
|
var status: LiveEventStatus? = nil
|
||||||
|
var currentParticipants: Int? = nil
|
||||||
|
var totalParticipants: Int? = nil
|
||||||
|
var pinned: String? = nil
|
||||||
|
var hashtags: [String]? = nil
|
||||||
|
var publicKeys: [Pubkey] = []
|
||||||
|
|
||||||
|
static func parse(from ev: NostrEvent) -> LiveEvent {
|
||||||
|
var liveEvent = LiveEvent(event: ev)
|
||||||
|
|
||||||
|
for tag in ev.tags {
|
||||||
|
guard tag.count >= 2 else { continue }
|
||||||
|
switch tag[0].string() {
|
||||||
|
case "title": liveEvent.title = tag[1].string()
|
||||||
|
case "d": liveEvent.uuid = tag[1].string()
|
||||||
|
case "image": liveEvent.image = URL(string: tag[1].string())
|
||||||
|
case "summary": liveEvent.summary = tag[1].string()
|
||||||
|
case "streaming": liveEvent.streaming = URL(string: tag[1].string())
|
||||||
|
case "recording": liveEvent.recording = URL(string: tag[1].string())
|
||||||
|
case "starts": liveEvent.starts = tag[1].string()
|
||||||
|
case "ends": liveEvent.ends = tag[1].string()
|
||||||
|
case "status":
|
||||||
|
if tag[1].string() == "planned" {
|
||||||
|
liveEvent.status = .planned
|
||||||
|
} else if tag[1].string() == "live" {
|
||||||
|
liveEvent.status = .live
|
||||||
|
} else if tag[1].string() == "ended" {
|
||||||
|
liveEvent.status = .ended
|
||||||
|
}
|
||||||
|
case "current_participants": liveEvent.currentParticipants = Int(tag[1].string())
|
||||||
|
case "total_participants": liveEvent.totalParticipants = Int(tag[1].string())
|
||||||
|
case "pinned": liveEvent.pinned = tag[1].string()
|
||||||
|
case "t":
|
||||||
|
if (liveEvent.hashtags?.append(tag[1].string())) == nil {
|
||||||
|
liveEvent.hashtags = [tag[1].string()]
|
||||||
|
}
|
||||||
|
case "p":
|
||||||
|
liveEvent.publicKeys.append(Pubkey(Data(hex: tag[1].string())))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return liveEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
97
damus/Features/Live/LiveStream/Models/LiveEventModel.swift
Normal file
97
damus/Features/Live/LiveStream/Models/LiveEventModel.swift
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// LiveEventModel.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/25/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// The data model for the LiveEventHome view
|
||||||
|
class LiveEventModel: ObservableObject {
|
||||||
|
var events: EventHolder
|
||||||
|
@Published var loading: Bool = false
|
||||||
|
|
||||||
|
let damus_state: DamusState
|
||||||
|
var subscriptionTask: Task<Void, any Error>? = nil
|
||||||
|
var seen_dtag: Set<String> = Set()
|
||||||
|
|
||||||
|
init(damus_state: DamusState) {
|
||||||
|
self.damus_state = damus_state
|
||||||
|
self.events = EventHolder(on_queue: { ev in
|
||||||
|
preload_events(state: damus_state, events: [ev])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func filter_muted() {
|
||||||
|
events.filter { should_show_event(state: damus_state, ev: $0) }
|
||||||
|
self.objectWillChange.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to set the `loading` member in the correct actor
|
||||||
|
@MainActor
|
||||||
|
private func set(loading: Bool) {
|
||||||
|
self.loading = loading
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribe() {
|
||||||
|
subscriptionTask?.cancel()
|
||||||
|
|
||||||
|
subscriptionTask = Task {
|
||||||
|
await self.set(loading: true)
|
||||||
|
|
||||||
|
var live_event_filter = NostrFilter(kinds: [.live])
|
||||||
|
live_event_filter.until = UInt32(Date.now.timeIntervalSince1970)
|
||||||
|
let calendar = Calendar.current
|
||||||
|
let twoWeeksAgo = calendar.date(byAdding: .day, value: -14, to: Date())!
|
||||||
|
live_event_filter.since = UInt32(twoWeeksAgo.timeIntervalSince1970)
|
||||||
|
|
||||||
|
let to_relays = await damus_state.nostrNetwork.ourRelayDescriptors
|
||||||
|
.map { $0.url }
|
||||||
|
.filter { !damus_state.relay_filters.is_filtered(timeline: .search, relay_id: $0) }
|
||||||
|
|
||||||
|
for await item in damus_state.nostrNetwork.reader.advancedStream(filters: [live_event_filter], to: to_relays) {
|
||||||
|
switch item {
|
||||||
|
case .event(let lender):
|
||||||
|
await lender.justUseACopy({ await handle_event(ev: $0) })
|
||||||
|
case .eose:
|
||||||
|
continue
|
||||||
|
case .ndbEose:
|
||||||
|
await self.set(loading: false)
|
||||||
|
case .networkEose:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func unsubscribe() {
|
||||||
|
self.set(loading: false)
|
||||||
|
subscriptionTask?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(ev: NostrEvent) async {
|
||||||
|
let should_show_event = await should_show_event(state: damus_state, ev: ev)
|
||||||
|
if ev.is_textlike && should_show_event && !ev.is_reply()
|
||||||
|
{
|
||||||
|
for tag in ev.tags {
|
||||||
|
guard tag.count >= 2 else { continue }
|
||||||
|
if tag[0].string() == "d" {
|
||||||
|
if seen_dtag.contains(tag[1].string()) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
seen_dtag.insert(tag[1].string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
if self.events.insert(ev) {
|
||||||
|
self.objectWillChange.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamBanner.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct LiveStreamBanner: View {
|
||||||
|
let state: DamusState
|
||||||
|
let options: EventViewOptions
|
||||||
|
var image: URL? = nil
|
||||||
|
var preview: Bool
|
||||||
|
|
||||||
|
func Placeholder(url: URL, preview: Bool) -> some View {
|
||||||
|
Group {
|
||||||
|
if let meta = state.events.lookup_img_metadata(url: url),
|
||||||
|
case .processed(let blurhash) = meta.state {
|
||||||
|
Image(uiImage: blurhash)
|
||||||
|
.resizable()
|
||||||
|
.frame(minWidth: UIScreen.main.bounds.width, minHeight: preview ? 200 : 200, maxHeight: preview ? 200 : 200)
|
||||||
|
} else {
|
||||||
|
DamusColors.adaptableWhite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func titleImage(url: URL, preview: Bool) -> some View {
|
||||||
|
KFAnimatedImage(url)
|
||||||
|
.callbackQueue(.dispatch(.global(qos:.background)))
|
||||||
|
.backgroundDecode(true)
|
||||||
|
.imageContext(.note, disable_animation: state.settings.disable_animation)
|
||||||
|
.image_fade(duration: 0.25)
|
||||||
|
.cancelOnDisappear(true)
|
||||||
|
.configure { view in
|
||||||
|
view.framePreloadCount = 3
|
||||||
|
}
|
||||||
|
.background {
|
||||||
|
Placeholder(url: url, preview: preview)
|
||||||
|
}
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(minWidth: UIScreen.main.bounds.width, minHeight: preview ? 200 : 200, maxHeight: preview ? 200 : 200)
|
||||||
|
.kfClickable()
|
||||||
|
.cornerRadius(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let url = image {
|
||||||
|
if (self.options.contains(.no_media)) {
|
||||||
|
EmptyView()
|
||||||
|
} else {
|
||||||
|
titleImage(url: url, preview: preview)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Text(NSLocalizedString("No cover image", comment: "Text letting user know there is no cover image."))
|
||||||
|
.bold()
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.frame(width: UIScreen.main.bounds.width, height: 200)
|
||||||
|
.background(DamusGradient.gradient.opacity(0.75))
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamProfile.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveStreamProfile: View {
|
||||||
|
var state: DamusState
|
||||||
|
var pubkey: Pubkey
|
||||||
|
var size: CGFloat = 25
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
ProfilePicView(pubkey: pubkey, size: size, highlight: .custom(DamusColors.neutral3, 1.0), profiles: state.profiles, disable_animation: state.settings.disable_animation, show_zappability: true, damusState: state)
|
||||||
|
.onTapGesture {
|
||||||
|
state.nav.push(route: Route.ProfileByKey(pubkey: pubkey))
|
||||||
|
}
|
||||||
|
let profile_txn = state.profiles.lookup(id: pubkey)
|
||||||
|
let profile = profile_txn?.unsafeUnownedValue
|
||||||
|
let displayName = Profile.displayName(profile: profile, pubkey: pubkey)
|
||||||
|
switch displayName {
|
||||||
|
case .one(let one):
|
||||||
|
Text(one)
|
||||||
|
.font(.subheadline).foregroundColor(.gray)
|
||||||
|
|
||||||
|
case .both(username: let username, displayName: let displayName):
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Text(verbatim: displayName)
|
||||||
|
.font(.subheadline).foregroundColor(.gray)
|
||||||
|
|
||||||
|
Text(verbatim: "@\(username)")
|
||||||
|
.font(.subheadline).foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamStatus.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveStreamStatus: View {
|
||||||
|
let status: LiveEventStatus
|
||||||
|
let starts: String?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
switch status {
|
||||||
|
case .planned:
|
||||||
|
Image("calendar")
|
||||||
|
.foregroundColor(Color.white)
|
||||||
|
|
||||||
|
if let starts = starts {
|
||||||
|
Text("\(starts)")
|
||||||
|
.foregroundColor(Color.white)
|
||||||
|
.bold()
|
||||||
|
.glow()
|
||||||
|
} else {
|
||||||
|
Text("\(status.rawValue)")
|
||||||
|
.foregroundColor(Color.white)
|
||||||
|
.bold()
|
||||||
|
}
|
||||||
|
case .live:
|
||||||
|
Image("record")
|
||||||
|
.foregroundColor(Color.red)
|
||||||
|
.glow()
|
||||||
|
|
||||||
|
Text("\(status.rawValue)")
|
||||||
|
.foregroundColor(DamusColors.adaptableWhite)
|
||||||
|
.bold()
|
||||||
|
case .ended:
|
||||||
|
Text("\(status.rawValue)")
|
||||||
|
.foregroundColor(DamusColors.adaptableWhite)
|
||||||
|
.bold()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.padding(.horizontal, 7)
|
||||||
|
.background(DamusColors.adaptableBlack.opacity(0.5))
|
||||||
|
.cornerRadius(10)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamViewers.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveStreamViewers: View {
|
||||||
|
let state: DamusState
|
||||||
|
var currentParticipants: Int
|
||||||
|
var preview: Bool
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
let viewerCount = currentParticipants
|
||||||
|
let nounString = pluralizedString(key: "viewer_count", count: viewerCount)
|
||||||
|
let nounText = Text(verbatim: nounString).font(.subheadline).foregroundColor(DamusColors.adaptableWhite)
|
||||||
|
|
||||||
|
if preview {
|
||||||
|
Text("\(Text(verbatim: viewerCount.formatted()).font(.subheadline.weight(.medium))) \(nounText)", comment: "Sentence composed of 2 variables to describe how many people are viewing the live event. In source English, the first variable is the number of viewers, and the second variable is 'viewer' or 'viewers'.")
|
||||||
|
.foregroundColor(DamusColors.adaptableWhite)
|
||||||
|
} else {
|
||||||
|
Image("user")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 15, height: 15)
|
||||||
|
Text("\(Text(verbatim: viewerCount.formatted()).font(.subheadline.weight(.medium)))", comment: "number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.vertical, preview ? 2 : 0)
|
||||||
|
.padding(.horizontal, preview ? 7 : 0)
|
||||||
|
.background(preview ? DamusColors.adaptableBlack.opacity(0.5) : .clear)
|
||||||
|
.cornerRadius(preview ? 10 : 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamHomeView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/25/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import CryptoKit
|
||||||
|
import NaturalLanguage
|
||||||
|
|
||||||
|
struct LiveStreamHomeView: View {
|
||||||
|
let damus_state: DamusState
|
||||||
|
@StateObject var model: LiveEventModel
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
func content_filter(_ fstate: FilterState) -> ((NostrEvent) -> Bool) {
|
||||||
|
var filters = ContentFilters.defaults(damus_state: damus_state)
|
||||||
|
filters.append(fstate.filter)
|
||||||
|
return ContentFilters(filters: filters).filter
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
LiveStreamTimelineView<AnyView>(events: model.events, loading: $model.loading, damus: damus_state, filter:content_filter(FilterState.live))
|
||||||
|
}
|
||||||
|
.padding(.bottom)
|
||||||
|
.refreshable {
|
||||||
|
// Fetch new information by unsubscribing and resubscribing to the relay
|
||||||
|
model.unsubscribe()
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.new_mutes)) { _ in
|
||||||
|
self.model.filter_muted()
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
model.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LiveStreamHomeView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
let state = test_damus_state
|
||||||
|
LiveStreamHomeView(damus_state: state, model: LiveEventModel(damus_state: state))
|
||||||
|
}
|
||||||
|
}
|
||||||
127
damus/Features/Live/LiveStream/Views/LiveStreamPreview.swift
Normal file
127
damus/Features/Live/LiveStream/Views/LiveStreamPreview.swift
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamPreview.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/10/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct LiveStreamPreviewBody: View {
|
||||||
|
let state: DamusState
|
||||||
|
let event: LiveEvent
|
||||||
|
let options: EventViewOptions
|
||||||
|
let header: Bool
|
||||||
|
|
||||||
|
@ObservedObject var artifacts: NoteArtifactsModel
|
||||||
|
|
||||||
|
init(state: DamusState, ev: LiveEvent, options: EventViewOptions, header: Bool) {
|
||||||
|
self.state = state
|
||||||
|
self.event = ev
|
||||||
|
self.options = options
|
||||||
|
self.header = header
|
||||||
|
|
||||||
|
self._artifacts = ObservedObject(wrappedValue: state.events.get_cache_data(ev.event.id).artifacts_model)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(state: DamusState, ev: NostrEvent, options: EventViewOptions, header: Bool) {
|
||||||
|
self.state = state
|
||||||
|
self.event = LiveEvent.parse(from: ev)
|
||||||
|
self.options = options
|
||||||
|
self.header = header
|
||||||
|
|
||||||
|
self._artifacts = ObservedObject(wrappedValue: state.events.get_cache_data(ev.id).artifacts_model)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if event.status == .live {
|
||||||
|
if let streamingURL = event.streaming {
|
||||||
|
if streamingURL.absoluteString.hasSuffix(".m3u8") {
|
||||||
|
Group {
|
||||||
|
if options.contains(.wide) {
|
||||||
|
Main.padding(.horizontal)
|
||||||
|
} else {
|
||||||
|
Main
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Main: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
|
||||||
|
ZStack(alignment: .topLeading) {
|
||||||
|
if state.settings.media_previews {
|
||||||
|
LiveStreamBanner(state: state, options: options, image: event.image, preview: true)
|
||||||
|
}
|
||||||
|
VStack {
|
||||||
|
if let status = event.status {
|
||||||
|
LiveStreamStatus(status: status, starts: event.starts)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
LiveStreamViewers(state: state, currentParticipants: event.currentParticipants ?? 0, preview: true)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(minWidth: UIScreen.main.bounds.width, minHeight: 200, maxHeight: 200)
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
LiveStreamProfile(state: state, pubkey: event.event.pubkey)
|
||||||
|
|
||||||
|
Text(event.title ?? NSLocalizedString("Untitled", comment: "Title of follow list event if it is untitled."))
|
||||||
|
.font(header ? .title : .headline)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
|
||||||
|
EventTags(tags: event.hashtags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LiveStreamPreview: View {
|
||||||
|
let state: DamusState
|
||||||
|
let event: LiveEvent
|
||||||
|
let options: EventViewOptions
|
||||||
|
|
||||||
|
init(state: DamusState, ev: NostrEvent, options: EventViewOptions) {
|
||||||
|
self.state = state
|
||||||
|
self.event = LiveEvent.parse(from: ev)
|
||||||
|
self.options = options.union(.no_mentions)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let _ = print(event)
|
||||||
|
LiveStreamPreviewBody(state: state, ev: event, options: options, header: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let test_live_event = LiveEvent.parse(from: NostrEvent(
|
||||||
|
content: "",
|
||||||
|
keypair: test_keypair,
|
||||||
|
kind: NostrKind.live.rawValue,
|
||||||
|
tags: [
|
||||||
|
["title", "DAMUSES MEETING"],
|
||||||
|
["summary", "Damus Team Meeting"],
|
||||||
|
["image", "https://damus.io/img/logo.png"],
|
||||||
|
["streaming", "https://ome.mapboss.co.th/live/local_019865b4-6814-71af-b86d-17d0c96d7867/llhls.m3u8"],
|
||||||
|
["recording", "https://damus.io"],
|
||||||
|
["status", "live"],
|
||||||
|
["t", "meeting"],
|
||||||
|
["t", "damus"]
|
||||||
|
])!
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
struct LiveStreamPreview_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
VStack {
|
||||||
|
LiveStreamPreview(state: test_damus_state, ev: test_live_event.event, options: [])
|
||||||
|
}
|
||||||
|
.frame(height: 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
140
damus/Features/Live/LiveStream/Views/LiveStreamTimeline.swift
Normal file
140
damus/Features/Live/LiveStream/Views/LiveStreamTimeline.swift
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamTimeline.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/23/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveStreamTimelineView<Content: View>: View {
|
||||||
|
@ObservedObject var events: EventHolder
|
||||||
|
@Binding var loading: Bool
|
||||||
|
|
||||||
|
let damus: DamusState
|
||||||
|
let filter: (NostrEvent) -> Bool
|
||||||
|
let content: Content?
|
||||||
|
let apply_mute_rules: Bool
|
||||||
|
|
||||||
|
init(events: EventHolder, loading: Binding<Bool>, headerHeight: Binding<CGFloat>, headerOffset: Binding<CGFloat>, damus: DamusState, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true, content: (() -> Content)? = nil) {
|
||||||
|
self.events = events
|
||||||
|
self._loading = loading
|
||||||
|
self.damus = damus
|
||||||
|
self.filter = filter
|
||||||
|
self.apply_mute_rules = apply_mute_rules
|
||||||
|
self.content = content?()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(events: EventHolder, loading: Binding<Bool>, damus: DamusState, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true, content: (() -> Content)? = nil) {
|
||||||
|
self.events = events
|
||||||
|
self._loading = loading
|
||||||
|
self.damus = damus
|
||||||
|
self.filter = filter
|
||||||
|
self.apply_mute_rules = apply_mute_rules
|
||||||
|
self.content = content?()
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollViewReader { scroller in
|
||||||
|
ScrollView {
|
||||||
|
if let content {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Happening Now")
|
||||||
|
.font(.title2)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
Text("Live events going on right now")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 5)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
Color.clear
|
||||||
|
.id("startblock")
|
||||||
|
.frame(height: 0)
|
||||||
|
|
||||||
|
LiveStreamInnerView(events: events, damus: damus, filter: loading ? { _ in true } : filter, apply_mute_rules: self.apply_mute_rules)
|
||||||
|
.redacted(reason: loading ? .placeholder : [])
|
||||||
|
.shimmer(loading)
|
||||||
|
.disabled(loading)
|
||||||
|
.background {
|
||||||
|
GeometryReader { proxy -> Color in
|
||||||
|
handle_scroll_queue(proxy, queue: self.events)
|
||||||
|
return Color.clear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.coordinateSpace(name: "scroll")
|
||||||
|
.onReceive(handle_notify(.scroll_to_top)) { () in
|
||||||
|
events.flush()
|
||||||
|
self.events.set_should_queue(false)
|
||||||
|
scroll_to_event(scroller: scroller, id: "startblock", delay: 0.0, animate: true, anchor: .top)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
events.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LiveStreamInnerView: View {
|
||||||
|
@ObservedObject var events: EventHolder
|
||||||
|
let state: DamusState
|
||||||
|
let filter: (NostrEvent) -> Bool
|
||||||
|
|
||||||
|
init(events: EventHolder, damus: DamusState, filter: @escaping (NostrEvent) -> Bool, apply_mute_rules: Bool = true) {
|
||||||
|
self.events = events
|
||||||
|
self.state = damus
|
||||||
|
self.filter = apply_mute_rules ? { filter($0) && !damus.mutelist_manager.is_event_muted($0) } : filter
|
||||||
|
}
|
||||||
|
|
||||||
|
var event_options: EventViewOptions {
|
||||||
|
if self.state.settings.truncate_timeline_text {
|
||||||
|
return [.wide, .truncate_content]
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.wide]
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
LazyVStack(spacing: 0) {
|
||||||
|
let events = self.events.events
|
||||||
|
if events.isEmpty {
|
||||||
|
EmptyTimelineView()
|
||||||
|
} else {
|
||||||
|
let evs = events.filter(filter)
|
||||||
|
let indexed = Array(zip(evs, 0...))
|
||||||
|
ForEach(indexed, id: \.0.id) { tup in
|
||||||
|
let ev = tup.0
|
||||||
|
let ind = tup.1
|
||||||
|
if ev.kind == NostrKind.live.rawValue {
|
||||||
|
LiveStreamPreview(state: state, ev: ev, options: event_options)
|
||||||
|
.onTapGesture {
|
||||||
|
state.nav.push(route: Route.LiveEvent(LiveEvent: ev, model: LiveEventModel(damus_state: state)))
|
||||||
|
}
|
||||||
|
.padding(.top, 7)
|
||||||
|
.onAppear {
|
||||||
|
let to_preload =
|
||||||
|
Array([indexed[safe: ind+1]?.0,
|
||||||
|
indexed[safe: ind+2]?.0,
|
||||||
|
indexed[safe: ind+3]?.0,
|
||||||
|
indexed[safe: ind+4]?.0,
|
||||||
|
indexed[safe: ind+5]?.0
|
||||||
|
].compactMap({ $0 }))
|
||||||
|
|
||||||
|
preload_events(state: state, events: to_preload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.bottom, 50)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
150
damus/Features/Live/LiveStream/Views/LiveStreamView.swift
Normal file
150
damus/Features/Live/LiveStream/Views/LiveStreamView.swift
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
//
|
||||||
|
// LiveStreamView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/25/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct LiveStreamView: View {
|
||||||
|
let state: DamusState
|
||||||
|
let event: LiveEvent
|
||||||
|
@StateObject var model: LiveEventModel
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
@Environment(\.presentationMode) var presentationMode
|
||||||
|
|
||||||
|
@ObservedObject var artifacts: NoteArtifactsModel
|
||||||
|
|
||||||
|
|
||||||
|
@State private var dragOffset: CGSize = .zero
|
||||||
|
@State private var isDragging = false
|
||||||
|
@State private var currentVideoModel: DamusVideoPlayer?
|
||||||
|
|
||||||
|
init(state: DamusState, ev: LiveEvent, model: LiveEventModel) {
|
||||||
|
self.state = state
|
||||||
|
self.event = ev
|
||||||
|
self._model = StateObject(wrappedValue: model)
|
||||||
|
|
||||||
|
self._artifacts = ObservedObject(wrappedValue: state.events.get_cache_data(ev.event.id).artifacts_model)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(state: DamusState, ev: NostrEvent, model: LiveEventModel) {
|
||||||
|
self.state = state
|
||||||
|
self.event = LiveEvent.parse(from: ev)
|
||||||
|
self._model = StateObject(wrappedValue: model)
|
||||||
|
|
||||||
|
self._artifacts = ObservedObject(wrappedValue: state.events.get_cache_data(ev.id).artifacts_model)
|
||||||
|
}
|
||||||
|
|
||||||
|
func content_filter(_ pubkeys: [Pubkey]) -> ((NostrEvent) -> Bool) {
|
||||||
|
var filters = ContentFilters.defaults(damus_state: self.state)
|
||||||
|
filters.append({ pubkeys.contains($0.pubkey) })
|
||||||
|
return ContentFilters(filters: filters).filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupVideoModel() {
|
||||||
|
if let streamingURL = event.streaming {
|
||||||
|
currentVideoModel = state.video.get_player(for: streamingURL)
|
||||||
|
// currentVideoModel = state.video.get_player(for: streamingURL, title: event.title ?? "Untitled", link: streamingURL.absoluteString, artist: "Nostrich", artwork: event.image?.absoluteString ?? "")
|
||||||
|
} else if let recordingURL = event.recording {
|
||||||
|
currentVideoModel = model.damus_state.video.get_player(for: recordingURL)
|
||||||
|
// currentVideoModel = model.damus_state.video.get_player(for: recordingURL, title: event.title ?? "Untitled", link: recordingURL.absoluteString, artist: "Nostrich", artwork: event.image?.absoluteString ?? "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dragGesture: some Gesture {
|
||||||
|
DragGesture()
|
||||||
|
.onChanged { value in
|
||||||
|
if value.translation.height > 0 {
|
||||||
|
dragOffset = value.translation
|
||||||
|
isDragging = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onEnded { value in
|
||||||
|
isDragging = false
|
||||||
|
|
||||||
|
if value.translation.height > 100 {
|
||||||
|
withAnimation(.easeOut(duration: 0.3)) {
|
||||||
|
dragOffset.height = UIScreen.main.bounds.height
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
withAnimation(.spring()) {
|
||||||
|
dragOffset = .zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
LiveEventHeader
|
||||||
|
.highPriorityGesture(dragGesture, including: .all)
|
||||||
|
|
||||||
|
LiveChatHomeView(state: state, event: event, model: LiveChatModel(damus_state: state, root: event.event.pubkey.hex(), dtag: event.uuid ?? ""))
|
||||||
|
.scrollDismissesKeyboard(.immediately)
|
||||||
|
}
|
||||||
|
.offset(y: dragOffset.height)
|
||||||
|
.opacity(isDragging ? Double(1 - min(abs(dragOffset.height) / 250, 0.5)) : 1.0)
|
||||||
|
.animation(.interactiveSpring(), value: dragOffset)
|
||||||
|
.navigationBarBackButtonHidden(true)
|
||||||
|
.onAppear {
|
||||||
|
notify(.display_tabbar(false))
|
||||||
|
model.subscribe()
|
||||||
|
setupVideoModel()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
notify(.display_tabbar(true))
|
||||||
|
model.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var LiveEventHeader: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
|
||||||
|
ZStack {
|
||||||
|
if let videoModel = currentVideoModel {
|
||||||
|
DamusVideoPlayerView(
|
||||||
|
model: videoModel,
|
||||||
|
coordinator: state.video,
|
||||||
|
style: .preview(on_tap: {})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
LiveStreamBanner(state: state, options: EventViewOptions(), image: event.image, preview: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: UIScreen.main.bounds.width, height: 250)
|
||||||
|
.fixedSize(horizontal: true, vertical: true)
|
||||||
|
.background(Color.black)
|
||||||
|
|
||||||
|
if !event.publicKeys.isEmpty {
|
||||||
|
LiveStreamProfile(state: state, pubkey: event.publicKeys[0], size: 35)
|
||||||
|
} else {
|
||||||
|
LiveStreamProfile(state: state, pubkey: event.event.pubkey, size: 35)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let title = event.title {
|
||||||
|
Text(title)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.padding(.horizontal, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO DO: Add description in sheet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct LiveStreamView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
LiveStreamView(state: test_damus_state, ev: test_live_event, model: LiveEventModel(damus_state: test_damus_state))
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ struct EventProfileName: View {
|
|||||||
|
|
||||||
let size: EventViewKind
|
let size: EventViewKind
|
||||||
|
|
||||||
init(pubkey: Pubkey, damus: DamusState, size: EventViewKind = .normal) {
|
init(pubkey: Pubkey, damus: DamusState, size: EventViewKind) {
|
||||||
self.damus_state = damus
|
self.damus_state = damus
|
||||||
self.pubkey = pubkey
|
self.pubkey = pubkey
|
||||||
self.size = size
|
self.size = size
|
||||||
@@ -68,11 +68,15 @@ struct EventProfileName: View {
|
|||||||
case .one(let one):
|
case .one(let one):
|
||||||
Text(one)
|
Text(one)
|
||||||
.font(.body.weight(.bold))
|
.font(.body.weight(.bold))
|
||||||
|
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size))
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
case .both(username: let username, displayName: let displayName):
|
case .both(username: let username, displayName: let displayName):
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
Text(verbatim: displayName)
|
Text(verbatim: displayName)
|
||||||
.font(.body.weight(.bold))
|
.font(.body.weight(.bold))
|
||||||
|
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size))
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
Text(verbatim: "@\(username)")
|
Text(verbatim: "@\(username)")
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
@@ -86,17 +90,18 @@ struct EventProfileName: View {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if size != .small {
|
||||||
|
if let frend = friend_type {
|
||||||
|
FriendIcon(friend: frend)
|
||||||
|
}
|
||||||
|
|
||||||
if let frend = friend_type {
|
if onlyzapper(profile) {
|
||||||
FriendIcon(friend: frend)
|
Image("zap-hashtag")
|
||||||
|
.frame(width: 14, height: 14)
|
||||||
|
}
|
||||||
|
|
||||||
|
SupporterBadge(percent: self.supporter_percentage(), purple_account: self.purple_account, style: .compact)
|
||||||
}
|
}
|
||||||
|
|
||||||
if onlyzapper(profile) {
|
|
||||||
Image("zap-hashtag")
|
|
||||||
.frame(width: 14, height: 14)
|
|
||||||
}
|
|
||||||
|
|
||||||
SupporterBadge(percent: self.supporter_percentage(), purple_account: self.purple_account, style: .compact)
|
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.profile_updated)) { update in
|
.onReceive(handle_notify(.profile_updated)) { update in
|
||||||
if update.pubkey != pubkey {
|
if update.pubkey != pubkey {
|
||||||
@@ -132,6 +137,6 @@ struct EventProfileName: View {
|
|||||||
|
|
||||||
struct EventProfileName_Previews: PreviewProvider {
|
struct EventProfileName_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
EventProfileName(pubkey: test_note.pubkey, damus: test_damus_state)
|
EventProfileName(pubkey: test_note.pubkey, damus: test_damus_state, size: .normal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ struct ProfileView: View {
|
|||||||
filters.append({ profile.pubkey == $0.pubkey })
|
filters.append({ profile.pubkey == $0.pubkey })
|
||||||
case .conversations:
|
case .conversations:
|
||||||
filters.append({ profile.conversation_events.contains($0.id) } )
|
filters.append({ profile.conversation_events.contains($0.id) } )
|
||||||
|
case .live, .live_chat:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return ContentFilters(filters: filters).filter
|
return ContentFilters(filters: filters).filter
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,6 +365,11 @@ class UserSettingsStore: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Damus Labs Experiments
|
||||||
|
@Setting(key: "live", default_value: false)
|
||||||
|
var live: Bool
|
||||||
|
|
||||||
|
|
||||||
// MARK: Internal, hidden settings
|
// MARK: Internal, hidden settings
|
||||||
|
|
||||||
// TODO: Get rid of this once we have NostrDB query capabilities integrated
|
// TODO: Get rid of this once we have NostrDB query capabilities integrated
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ enum FilterState : Int {
|
|||||||
case posts_and_replies = 1
|
case posts_and_replies = 1
|
||||||
case conversations = 2
|
case conversations = 2
|
||||||
case follow_list = 3
|
case follow_list = 3
|
||||||
|
case live = 4
|
||||||
|
case live_chat = 5
|
||||||
|
|
||||||
func filter(ev: NostrEvent) -> Bool {
|
func filter(ev: NostrEvent) -> Bool {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -39,6 +41,10 @@ enum FilterState : Int {
|
|||||||
return true
|
return true
|
||||||
case .follow_list:
|
case .follow_list:
|
||||||
return ev.known_kind == .follow_list
|
return ev.known_kind == .follow_list
|
||||||
|
case .live:
|
||||||
|
return ev.known_kind == .live
|
||||||
|
case .live_chat:
|
||||||
|
return ev.known_kind == .live_chat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,6 +231,8 @@ class HomeModel: ContactsDelegate, ObservableObject {
|
|||||||
break
|
break
|
||||||
case .interest_list:
|
case .interest_list:
|
||||||
break // Don't care for now
|
break // Don't care for now
|
||||||
|
case .live, .live_chat:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,12 @@ struct SideMenuView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if damus_state.settings.live {
|
||||||
|
NavigationLink(value: Route.LiveEvents(model: LiveEventModel(damus_state: damus_state))) {
|
||||||
|
navLabel(title: NSLocalizedString("Live", comment: "Sidebar menu label for live events view."), img: "record")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NavigationLink(value: Route.MuteList) {
|
NavigationLink(value: Route.MuteList) {
|
||||||
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
|
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
|
||||||
}
|
}
|
||||||
|
|||||||
33
damus/Shared/Components/EventTags.swift
Normal file
33
damus/Shared/Components/EventTags.swift
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// EventTags.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 8/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct EventTags: View {
|
||||||
|
var tags: [String]?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView(.horizontal) {
|
||||||
|
HStack {
|
||||||
|
ForEach(tags ?? [], id: \.self) { tag in
|
||||||
|
Text(tag)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.padding(EdgeInsets(top: 2, leading: 8, bottom: 2, trailing: 8))
|
||||||
|
.background(DamusColors.neutral1)
|
||||||
|
.cornerRadius(20)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 20)
|
||||||
|
.stroke(DamusColors.neutral3, lineWidth: 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.padding(.horizontal, 5)
|
||||||
|
}
|
||||||
|
.padding(.bottom, 5)
|
||||||
|
.scrollIndicators(.hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
31
damus/Shared/Modifiers/Glow.swift
Normal file
31
damus/Shared/Modifiers/Glow.swift
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Glow.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by eric on 7/26/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct Glow: ViewModifier {
|
||||||
|
@State private var effect = false
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
ZStack {
|
||||||
|
content
|
||||||
|
.blur(radius: effect ? 15 : 5)
|
||||||
|
.animation(.easeOut(duration: 0.5).repeatForever(), value: effect)
|
||||||
|
.onAppear {
|
||||||
|
effect.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func glow() -> some View {
|
||||||
|
modifier(Glow())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,8 @@ enum Route: Hashable {
|
|||||||
case NIP05DomainEvents(events: NIP05DomainEventsModel, nip05_domain_favicon: FaviconURL?)
|
case NIP05DomainEvents(events: NIP05DomainEventsModel, nip05_domain_favicon: FaviconURL?)
|
||||||
case NIP05DomainPubkeys(domain: String, nip05_domain_favicon: FaviconURL?, pubkeys: [Pubkey])
|
case NIP05DomainPubkeys(domain: String, nip05_domain_favicon: FaviconURL?, pubkeys: [Pubkey])
|
||||||
case FollowPack(followPack: NostrEvent, model: FollowPackModel, blur_imgs: Bool)
|
case FollowPack(followPack: NostrEvent, model: FollowPackModel, blur_imgs: Bool)
|
||||||
|
case LiveEvents(model: LiveEventModel)
|
||||||
|
case LiveEvent(LiveEvent: NostrEvent, model: LiveEventModel)
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func view(navigationCoordinator: NavigationCoordinator, damusState: DamusState) -> some View {
|
func view(navigationCoordinator: NavigationCoordinator, damusState: DamusState) -> some View {
|
||||||
@@ -137,7 +139,12 @@ enum Route: Hashable {
|
|||||||
NIP05DomainPubkeysView(damus_state: damusState, domain: domain, nip05_domain_favicon: nip05_domain_favicon, pubkeys: pubkeys)
|
NIP05DomainPubkeysView(damus_state: damusState, domain: domain, nip05_domain_favicon: nip05_domain_favicon, pubkeys: pubkeys)
|
||||||
case .FollowPack(let followPack, let followPackModel, let blur_imgs):
|
case .FollowPack(let followPack, let followPackModel, let blur_imgs):
|
||||||
FollowPackView(state: damusState, ev: followPack, model: followPackModel, blur_imgs: blur_imgs)
|
FollowPackView(state: damusState, ev: followPack, model: followPackModel, blur_imgs: blur_imgs)
|
||||||
|
case .LiveEvents(let model):
|
||||||
|
LiveStreamHomeView(damus_state: damusState, model: model)
|
||||||
|
case .LiveEvent(let liveEvent, let liveEventModel):
|
||||||
|
LiveStreamView(state: damusState, ev: liveEvent, model: liveEventModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Route, rhs: Route) -> Bool {
|
static func == (lhs: Route, rhs: Route) -> Bool {
|
||||||
@@ -249,6 +256,11 @@ enum Route: Hashable {
|
|||||||
case .FollowPack(let followPack, let followPackModel, let blur_imgs):
|
case .FollowPack(let followPack, let followPackModel, let blur_imgs):
|
||||||
hasher.combine("followPack")
|
hasher.combine("followPack")
|
||||||
hasher.combine(followPack.id)
|
hasher.combine(followPack.id)
|
||||||
|
case .LiveEvents(let model):
|
||||||
|
hasher.combine("liveEvents")
|
||||||
|
case .LiveEvent(let liveEvent, let liveEventModel):
|
||||||
|
hasher.combine("liveEvent")
|
||||||
|
hasher.combine(liveEvent.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,22 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>viewer_count</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@VIEWERS@</string>
|
||||||
|
<key>VIEWERS</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>d</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>viewer</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>viewers</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>follow_pack_user_count</key>
|
<key>follow_pack_user_count</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSStringLocalizedFormatKey</key>
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ class NdbNote: Codable, Equatable, Hashable {
|
|||||||
extension NdbNote {
|
extension NdbNote {
|
||||||
var is_textlike: Bool {
|
var is_textlike: Bool {
|
||||||
switch known_kind {
|
switch known_kind {
|
||||||
case .text, .chat, .longform, .highlight:
|
case .text, .chat, .longform, .highlight, .live, .live_chat:
|
||||||
true
|
true
|
||||||
default:
|
default:
|
||||||
false
|
false
|
||||||
|
|||||||
Reference in New Issue
Block a user