WIP NIP-A0 voice messages
This commit is contained in:
@@ -33,6 +33,10 @@
|
|||||||
3A515C542DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
3A515C542DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
||||||
3A515C552DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
3A515C552DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
||||||
3A515C562DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
3A515C562DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
|
||||||
|
3A7379D42E5D5C4A00DF8B4E /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */; };
|
||||||
|
3A7379D72E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
|
||||||
|
3A7379D82E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
|
||||||
|
3A7379D92E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
|
||||||
3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; };
|
3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; };
|
||||||
3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
|
3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
|
||||||
3A92C0FF2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
|
3A92C0FF2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
|
||||||
@@ -1923,6 +1927,7 @@
|
|||||||
3A66D927299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
3A66D927299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
3A66D928299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
3A66D928299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
3A66D929299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ja; path = ja.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
3A66D929299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ja; path = ja.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
|
3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusAudioPlayerView.swift; sourceTree = "<group>"; };
|
||||||
3A821C3E29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
3A821C3E29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
3A821C3F29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
3A821C3F29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
3A821C4029E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
3A821C4029E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
@@ -2731,6 +2736,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
3ACF94382DA9A52F00971A4E /* FaviconFinder in Frameworks */,
|
3ACF94382DA9A52F00971A4E /* FaviconFinder in Frameworks */,
|
||||||
|
3A7379D42E5D5C4A00DF8B4E /* DSWaveformImageViews in Frameworks */,
|
||||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
|
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
|
||||||
D7DB1FE42D5A9AC900CF06DA /* CryptoSwift in Frameworks */,
|
D7DB1FE42D5A9AC900CF06DA /* CryptoSwift in Frameworks */,
|
||||||
3A0A30BB2C21397A00F8C9BC /* EmojiPicker in Frameworks */,
|
3A0A30BB2C21397A00F8C9BC /* EmojiPicker in Frameworks */,
|
||||||
@@ -2824,6 +2830,14 @@
|
|||||||
path = Tips;
|
path = Tips;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
3A7379D52E5D5DF000DF8B4E /* Audio */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */,
|
||||||
|
);
|
||||||
|
path = Audio;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
3AA24800297E3DAE0090C62D /* Reposts */ = {
|
3AA24800297E3DAE0090C62D /* Reposts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -4392,6 +4406,7 @@
|
|||||||
children = (
|
children = (
|
||||||
5C78A79D2E303D2600CF177D /* Models */,
|
5C78A79D2E303D2600CF177D /* Models */,
|
||||||
4CFF8F6129CC9A80008DB934 /* Images */,
|
4CFF8F6129CC9A80008DB934 /* Images */,
|
||||||
|
3A7379D52E5D5DF000DF8B4E /* Audio */,
|
||||||
4C1A9A2829DDF53B00516EAC /* Video */,
|
4C1A9A2829DDF53B00516EAC /* Video */,
|
||||||
BA3759952ABCCF360018D73B /* Camera */,
|
BA3759952ABCCF360018D73B /* Camera */,
|
||||||
4C198DEA29F88C6B004C165C /* BlurHash */,
|
4C198DEA29F88C6B004C165C /* BlurHash */,
|
||||||
@@ -5060,6 +5075,7 @@
|
|||||||
D7C48C0A2D12DE0C00A3BACF /* SwiftyCrop */,
|
D7C48C0A2D12DE0C00A3BACF /* SwiftyCrop */,
|
||||||
D7DB1FE32D5A9AC900CF06DA /* CryptoSwift */,
|
D7DB1FE32D5A9AC900CF06DA /* CryptoSwift */,
|
||||||
3ACF94372DA9A52F00971A4E /* FaviconFinder */,
|
3ACF94372DA9A52F00971A4E /* FaviconFinder */,
|
||||||
|
3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */,
|
||||||
);
|
);
|
||||||
productName = damus;
|
productName = damus;
|
||||||
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
||||||
@@ -5271,6 +5287,7 @@
|
|||||||
D7C48C092D12DE0C00A3BACF /* XCRemoteSwiftPackageReference "SwiftyCrop" */,
|
D7C48C092D12DE0C00A3BACF /* XCRemoteSwiftPackageReference "SwiftyCrop" */,
|
||||||
D7DB1FE22D5A9AC900CF06DA /* XCRemoteSwiftPackageReference "CryptoSwift" */,
|
D7DB1FE22D5A9AC900CF06DA /* XCRemoteSwiftPackageReference "CryptoSwift" */,
|
||||||
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */,
|
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */,
|
||||||
|
3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@@ -5805,6 +5822,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 */,
|
||||||
|
3A7379D72E5D5E1900DF8B4E /* DamusAudioPlayerView.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 */,
|
||||||
@@ -6095,6 +6113,7 @@
|
|||||||
82D6FB092CD99F7900C925F4 /* SearchHeaderView.swift in Sources */,
|
82D6FB092CD99F7900C925F4 /* SearchHeaderView.swift in Sources */,
|
||||||
82D6FB0A2CD99F7900C925F4 /* DamusGradient.swift in Sources */,
|
82D6FB0A2CD99F7900C925F4 /* DamusGradient.swift in Sources */,
|
||||||
D7DB93052D66A44100DA1EE5 /* Undistractor.swift in Sources */,
|
D7DB93052D66A44100DA1EE5 /* Undistractor.swift in Sources */,
|
||||||
|
3A7379D92E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */,
|
||||||
82D6FB0C2CD99F7900C925F4 /* GoldSupportGradient.swift in Sources */,
|
82D6FB0C2CD99F7900C925F4 /* GoldSupportGradient.swift in Sources */,
|
||||||
82D6FB0D2CD99F7900C925F4 /* PinkGradient.swift in Sources */,
|
82D6FB0D2CD99F7900C925F4 /* PinkGradient.swift in Sources */,
|
||||||
82D6FB0E2CD99F7900C925F4 /* GrayGradient.swift in Sources */,
|
82D6FB0E2CD99F7900C925F4 /* GrayGradient.swift in Sources */,
|
||||||
@@ -6780,6 +6799,7 @@
|
|||||||
D73E5F092C6A97F4007EB227 /* ProfilePicView.swift in Sources */,
|
D73E5F092C6A97F4007EB227 /* ProfilePicView.swift in Sources */,
|
||||||
D73E5F0A2C6A97F4007EB227 /* ProfileView.swift in Sources */,
|
D73E5F0A2C6A97F4007EB227 /* ProfileView.swift in Sources */,
|
||||||
D73E5F0B2C6A97F4007EB227 /* ProfileNameView.swift in Sources */,
|
D73E5F0B2C6A97F4007EB227 /* ProfileNameView.swift in Sources */,
|
||||||
|
3A7379D82E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */,
|
||||||
D73E5F0C2C6A97F4007EB227 /* MaybeAnonPfpView.swift in Sources */,
|
D73E5F0C2C6A97F4007EB227 /* MaybeAnonPfpView.swift in Sources */,
|
||||||
D73E5F0D2C6A97F4007EB227 /* EventProfileName.swift in Sources */,
|
D73E5F0D2C6A97F4007EB227 /* EventProfileName.swift in Sources */,
|
||||||
D73E5F0E2C6A97F4007EB227 /* FriendIcon.swift in Sources */,
|
D73E5F0E2C6A97F4007EB227 /* FriendIcon.swift in Sources */,
|
||||||
@@ -7922,6 +7942,14 @@
|
|||||||
minimumVersion = 0.2.0;
|
minimumVersion = 0.2.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/dmrschmidt/DSWaveformImage";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 14.2.2;
|
||||||
|
};
|
||||||
|
};
|
||||||
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */ = {
|
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/will-lumley/FaviconFinder.git";
|
repositoryURL = "https://github.com/will-lumley/FaviconFinder.git";
|
||||||
@@ -8010,6 +8038,11 @@
|
|||||||
package = 3A0A30B92C21397A00F8C9BC /* XCRemoteSwiftPackageReference "EmojiPicker" */;
|
package = 3A0A30B92C21397A00F8C9BC /* XCRemoteSwiftPackageReference "EmojiPicker" */;
|
||||||
productName = EmojiPicker;
|
productName = EmojiPicker;
|
||||||
};
|
};
|
||||||
|
3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
|
||||||
|
productName = DSWaveformImageViews;
|
||||||
|
};
|
||||||
3ACF94372DA9A52F00971A4E /* FaviconFinder */ = {
|
3ACF94372DA9A52F00971A4E /* FaviconFinder */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */;
|
package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "1fc7e0b44329ba72cd285eeb022b5b92582cd01586b920d243cb0485c2e69dcc",
|
"originHash" : "8d71e78d1d7bdc5a85a38932a14f84af755a9e34aeab19f9d540bd11a7b32fbc",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "codescanner",
|
"identity" : "codescanner",
|
||||||
@@ -17,6 +17,15 @@
|
|||||||
"revision" : "e74bbbfbef939224b242ae7c342a90e60b88b5ce"
|
"revision" : "e74bbbfbef939224b242ae7c342a90e60b88b5ce"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dswaveformimage",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/dmrschmidt/DSWaveformImage",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4c56578ee10128ee2b2c04c9c5aa73812de722db",
|
||||||
|
"version" : "14.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "emojikit",
|
"identity" : "emojikit",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -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 voice_message = 1222
|
||||||
case mute_list = 10000
|
case mute_list = 10000
|
||||||
case relay_list = 10002
|
case relay_list = 10002
|
||||||
case interest_list = 10015
|
case interest_list = 10015
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class LoadableNostrEventViewModel: ObservableObject {
|
|||||||
guard let ev = await self.loadEvent(noteId: note_id) else { return .not_found }
|
guard let ev = await self.loadEvent(noteId: note_id) else { return .not_found }
|
||||||
guard let known_kind = ev.known_kind else { return .unknown_or_unsupported_kind }
|
guard let known_kind = ev.known_kind else { return .unknown_or_unsupported_kind }
|
||||||
switch known_kind {
|
switch known_kind {
|
||||||
case .text, .highlight:
|
case .text, .highlight, .voice_message:
|
||||||
return .loaded(route: Route.Thread(thread: ThreadModel(event: ev, damus_state: damus_state)))
|
return .loaded(route: Route.Thread(thread: ThreadModel(event: ev, damus_state: damus_state)))
|
||||||
case .dm:
|
case .dm:
|
||||||
let dm_model = damus_state.dms.lookup_or_create(ev.pubkey)
|
let dm_model = damus_state.dms.lookup_or_create(ev.pubkey)
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ func classify_url(_ url: URL) -> UrlType {
|
|||||||
return .media(.image(url))
|
return .media(.image(url))
|
||||||
case "mp4", "mov", "m3u8":
|
case "mp4", "mov", "m3u8":
|
||||||
return .media(.video(url))
|
return .media(.video(url))
|
||||||
|
case "m4a":
|
||||||
|
return .media(.audio(url))
|
||||||
default:
|
default:
|
||||||
return .link(url)
|
return .link(url)
|
||||||
}
|
}
|
||||||
@@ -452,6 +454,8 @@ enum UrlType {
|
|||||||
return url
|
return url
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
return url
|
return url
|
||||||
|
case .audio(let url):
|
||||||
|
return url
|
||||||
}
|
}
|
||||||
case .link(let url):
|
case .link(let url):
|
||||||
return url
|
return url
|
||||||
@@ -462,7 +466,7 @@ enum UrlType {
|
|||||||
switch self {
|
switch self {
|
||||||
case .media(let media_url):
|
case .media(let media_url):
|
||||||
switch media_url {
|
switch media_url {
|
||||||
case .image:
|
case .image, .audio:
|
||||||
return nil
|
return nil
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
return url
|
return url
|
||||||
@@ -478,14 +482,28 @@ enum UrlType {
|
|||||||
switch media_url {
|
switch media_url {
|
||||||
case .image(let url):
|
case .image(let url):
|
||||||
return url
|
return url
|
||||||
case .video:
|
case .video, .audio:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case .link:
|
case .link:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var is_audio: URL? {
|
||||||
|
switch self {
|
||||||
|
case .media(let media_url):
|
||||||
|
switch media_url {
|
||||||
|
case .audio(let url):
|
||||||
|
return url
|
||||||
|
case .image, .video:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case .link:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var is_link: URL? {
|
var is_link: URL? {
|
||||||
switch self {
|
switch self {
|
||||||
case .media:
|
case .media:
|
||||||
@@ -508,13 +526,16 @@ enum UrlType {
|
|||||||
enum MediaUrl {
|
enum MediaUrl {
|
||||||
case image(URL)
|
case image(URL)
|
||||||
case video(URL)
|
case video(URL)
|
||||||
|
case audio(URL)
|
||||||
|
|
||||||
var url: URL {
|
var url: URL {
|
||||||
switch self {
|
switch self {
|
||||||
case .image(let url):
|
case .image(let url):
|
||||||
return url
|
return url
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
return url
|
return url
|
||||||
|
case .audio(let url):
|
||||||
|
return url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ struct NoteContentView: View {
|
|||||||
Divider()
|
Divider()
|
||||||
.frame(height: 1)
|
.frame(height: 1)
|
||||||
switch artifacts.media[index] {
|
switch artifacts.media[index] {
|
||||||
case .image(let url), .video(let url):
|
case .image(let url), .video(let url), .audio(let url):
|
||||||
Text(abbreviateURL(url))
|
Text(abbreviateURL(url))
|
||||||
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size))
|
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size))
|
||||||
.foregroundStyle(DamusColors.neutral6)
|
.foregroundStyle(DamusColors.neutral6)
|
||||||
@@ -477,7 +477,7 @@ struct BlurOverlayView: View {
|
|||||||
let damus_state = damus_state
|
let damus_state = damus_state
|
||||||
{
|
{
|
||||||
switch artifacts.media[0] {
|
switch artifacts.media[0] {
|
||||||
case .image(let url), .video(let url):
|
case .image(let url), .video(let url), .audio(let url):
|
||||||
Text(abbreviateURL(url, maxLength: 30))
|
Text(abbreviateURL(url, maxLength: 30))
|
||||||
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size * 0.8))
|
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size * 0.8))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ProfileModel: ObservableObject, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func subscribe() {
|
func subscribe() {
|
||||||
var text_filter = NostrFilter(kinds: [.text, .longform, .highlight])
|
var text_filter = NostrFilter(kinds: [.text, .longform, .highlight, .voice_message])
|
||||||
var profile_filter = NostrFilter(kinds: [.contacts, .metadata, .boost])
|
var profile_filter = NostrFilter(kinds: [.contacts, .metadata, .boost])
|
||||||
var relay_list_filter = NostrFilter(kinds: [.relay_list], authors: [pubkey])
|
var relay_list_filter = NostrFilter(kinds: [.relay_list], authors: [pubkey])
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class ProfileModel: ObservableObject, Equatable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let conversation_kinds: [NostrKind] = [.text, .longform, .highlight]
|
let conversation_kinds: [NostrKind] = [.text, .longform, .highlight, .voice_message]
|
||||||
let limit: UInt32 = 500
|
let limit: UInt32 = 500
|
||||||
let conversations_filter_them = NostrFilter(kinds: conversation_kinds, pubkeys: [damus.pubkey], limit: limit, authors: [pubkey])
|
let conversations_filter_them = NostrFilter(kinds: conversation_kinds, pubkeys: [damus.pubkey], limit: limit, authors: [pubkey])
|
||||||
let conversations_filter_us = NostrFilter(kinds: conversation_kinds, pubkeys: [pubkey], limit: limit, authors: [damus.pubkey])
|
let conversations_filter_us = NostrFilter(kinds: conversation_kinds, pubkeys: [pubkey], limit: limit, authors: [damus.pubkey])
|
||||||
@@ -122,7 +122,7 @@ class ProfileModel: ObservableObject, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func add_event(_ ev: NostrEvent) {
|
private func add_event(_ ev: NostrEvent) {
|
||||||
if ev.is_textlike || ev.known_kind == .boost {
|
if ev.is_textlike || ev.known_kind == .boost || ev.known_kind == .voice_message {
|
||||||
if self.events.insert(ev) {
|
if self.events.insert(ev) {
|
||||||
self.objectWillChange.send()
|
self.objectWillChange.send()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ struct ProfileView: View {
|
|||||||
var filters = ContentFilters.defaults(damus_state: damus_state)
|
var filters = ContentFilters.defaults(damus_state: damus_state)
|
||||||
filters.append(fstate.filter)
|
filters.append(fstate.filter)
|
||||||
switch fstate {
|
switch fstate {
|
||||||
case .posts, .posts_and_replies, .follow_list:
|
case .posts, .posts_and_replies, .follow_list, .voice_messages:
|
||||||
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) } )
|
||||||
@@ -438,7 +438,8 @@ struct ProfileView: View {
|
|||||||
var tabs: [(String, FilterState)] {
|
var tabs: [(String, FilterState)] {
|
||||||
var tabs = [
|
var tabs = [
|
||||||
(NSLocalizedString("Notes", comment: "Label for filter for seeing only notes (instead of notes and replies)."), FilterState.posts),
|
(NSLocalizedString("Notes", comment: "Label for filter for seeing only notes (instead of notes and replies)."), FilterState.posts),
|
||||||
(NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies)
|
(NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies),
|
||||||
|
(NSLocalizedString("Voice", comment: "Label for filter for seeing voice messages."), FilterState.voice_messages)
|
||||||
]
|
]
|
||||||
if profile.pubkey != damus_state.pubkey && !profile.conversation_events.isEmpty {
|
if profile.pubkey != damus_state.pubkey && !profile.conversation_events.isEmpty {
|
||||||
tabs.append((NSLocalizedString("Conversations", comment: "Label for filter for seeing notes and replies that involve conversations between the signed in user and the current profile."), FilterState.conversations))
|
tabs.append((NSLocalizedString("Conversations", comment: "Label for filter for seeing notes and replies that involve conversations between the signed in user and the current profile."), FilterState.conversations))
|
||||||
@@ -469,6 +470,9 @@ struct ProfileView: View {
|
|||||||
if filter_state == FilterState.posts_and_replies {
|
if filter_state == FilterState.posts_and_replies {
|
||||||
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.posts_and_replies))
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.posts_and_replies))
|
||||||
}
|
}
|
||||||
|
if filter_state == FilterState.voice_messages {
|
||||||
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.voice_messages))
|
||||||
|
}
|
||||||
if filter_state == FilterState.conversations && !profile.conversation_events.isEmpty {
|
if filter_state == FilterState.conversations && !profile.conversation_events.isEmpty {
|
||||||
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.conversations))
|
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.conversations))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ 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 voice_messages = 4
|
||||||
|
|
||||||
func filter(ev: NostrEvent) -> Bool {
|
func filter(ev: NostrEvent) -> Bool {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -25,6 +26,8 @@ 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 .voice_messages:
|
||||||
|
return ev.known_kind == .voice_message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,8 @@ class HomeModel: ContactsDelegate {
|
|||||||
switch kind {
|
switch kind {
|
||||||
case .chat, .longform, .text, .highlight:
|
case .chat, .longform, .text, .highlight:
|
||||||
handle_text_event(sub_id: sub_id, ev)
|
handle_text_event(sub_id: sub_id, ev)
|
||||||
|
case .voice_message:
|
||||||
|
handle_voice_message_event(sub_id: sub_id, ev)
|
||||||
case .contacts:
|
case .contacts:
|
||||||
handle_contact_event(sub_id: sub_id, relay_id: relay_id, ev: ev)
|
handle_contact_event(sub_id: sub_id, relay_id: relay_id, ev: ev)
|
||||||
case .metadata:
|
case .metadata:
|
||||||
@@ -776,7 +778,28 @@ class HomeModel: ContactsDelegate {
|
|||||||
handle_notification(ev: ev)
|
handle_notification(ev: ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handle_voice_message_event(sub_id: String, _ ev: NostrEvent) {
|
||||||
|
guard should_show_event(state: damus_state, ev: ev) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: will we need to process this in other places like zap request contents, etc?
|
||||||
|
process_image_metadatas(cache: damus_state.events, ev: ev)
|
||||||
|
damus_state.replies.count_replies(ev, keypair: self.damus_state.keypair)
|
||||||
|
damus_state.events.insert(ev)
|
||||||
|
|
||||||
|
if let quoted_event = ev.referenced_quote_ids.first {
|
||||||
|
handle_quote_repost_event(ev, target: quoted_event.note_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sub_id == home_subid {
|
||||||
|
insert_home_event(ev)
|
||||||
|
} else if sub_id == notifications_subid {
|
||||||
|
handle_notification(ev: ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func got_new_dm(notifs: NewEventsBits, ev: NostrEvent) {
|
func got_new_dm(notifs: NewEventsBits, ev: NostrEvent) {
|
||||||
notification_status.new_events = notifs
|
notification_status.new_events = notifs
|
||||||
|
|
||||||
|
|||||||
44
damus/Shared/Media/Audio/DamusAudioPlayerView.swift
Normal file
44
damus/Shared/Media/Audio/DamusAudioPlayerView.swift
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// DamusAudioPlayerView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Terry Yiu on 8/25/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import DSWaveformImageViews
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct DamusAudioPlayerView: View {
|
||||||
|
let remoteURL: URL
|
||||||
|
@State var localURL: URL
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
WaveformView(audioURL: localURL) { shape in
|
||||||
|
shape.fill(.white)
|
||||||
|
shape.fill(.red).mask(alignment: .leading) {
|
||||||
|
Rectangle().frame(width: geometry.size.width * progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("Hello, World!")
|
||||||
|
.task {
|
||||||
|
URLSession.shared.downloadTask(with: remoteURL) { downloadedURL, urlResponse, error in
|
||||||
|
guard let downloadedURL = downloadedURL else { return }
|
||||||
|
|
||||||
|
let cachesFolderURL = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
|
||||||
|
let audioFileURL = cachesFolderURL!.appendingPathComponent("yourLocalAudioFile.m4a")
|
||||||
|
try? FileManager.default.copyItem(at: downloadedURL, to: audioFileURL)
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.localURL = audioFileURL
|
||||||
|
// self.WaveformView.waveformAudioURL = audioFileURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
DamusAudioPlayerView()
|
||||||
|
}
|
||||||
@@ -57,7 +57,9 @@ struct ImageContainerView: View {
|
|||||||
switch url {
|
switch url {
|
||||||
case .image(let url):
|
case .image(let url):
|
||||||
Img(url: url)
|
Img(url: url)
|
||||||
case .video(let url):
|
case .audio(let url):
|
||||||
|
DamusAudioPlayerView()
|
||||||
|
case .video(let url):
|
||||||
DamusVideoPlayerView(url: url, coordinator: video_coordinator, style: .no_controls(on_tap: nil))
|
DamusVideoPlayerView(url: url, coordinator: video_coordinator, style: .no_controls(on_tap: nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ class CarouselModel: ObservableObject {
|
|||||||
private func observe_video_sizes() {
|
private func observe_video_sizes() {
|
||||||
for media_url in urls {
|
for media_url in urls {
|
||||||
switch media_url {
|
switch media_url {
|
||||||
case .video(let url):
|
case .video(let url), .audio(let url):
|
||||||
let video_player = damus_state.video.get_player(for: url)
|
let video_player = damus_state.video.get_player(for: url)
|
||||||
if let video_size = video_player.video_size {
|
if let video_size = video_player.video_size {
|
||||||
self.media_size_information[url] = video_size // Set the initial size if available
|
self.media_size_information[url] = video_size // Set the initial size if available
|
||||||
@@ -302,6 +302,7 @@ class CarouselModel: ObservableObject {
|
|||||||
struct ImageCarousel<Content: View>: View {
|
struct ImageCarousel<Content: View>: View {
|
||||||
/// The event id of the note that this carousel is displaying
|
/// The event id of the note that this carousel is displaying
|
||||||
let evid: NoteId
|
let evid: NoteId
|
||||||
|
let event: NostrEvent
|
||||||
/// The model that holds information and state of this carousel
|
/// The model that holds information and state of this carousel
|
||||||
/// This is observed to update the view when the model changes
|
/// This is observed to update the view when the model changes
|
||||||
@ObservedObject var model: CarouselModel
|
@ObservedObject var model: CarouselModel
|
||||||
@@ -354,6 +355,8 @@ struct ImageCarousel<Content: View>: View {
|
|||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
present(full_screen_item: .full_screen_carousel(urls: model.urls, selectedIndex: $model.selectedIndex))
|
present(full_screen_item: .full_screen_carousel(urls: model.urls, selectedIndex: $model.selectedIndex))
|
||||||
}
|
}
|
||||||
|
case .audio(let url):
|
||||||
|
DamusAudioPlayerView()
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
let video_model = model.damus_state.video.get_player(for: url)
|
let video_model = model.damus_state.video.get_player(for: url)
|
||||||
DamusVideoPlayerView(
|
DamusVideoPlayerView(
|
||||||
|
|||||||
Reference in New Issue
Block a user