1
0
mirror of git://jb55.com/damus synced 2024-09-30 00:40:45 +00:00

mute: adding new structs/enums for new mute list

- Adding MuteItem & DamusDuration
- Changing RefId hashtag associated type from TagElem to Hashtag
    - This is done because in MuteItem, we can not create a RefId.hashtag TagElem instance since we don’t have a note associated with a given hashtag mute item.

Related: https://github.com/damus-io/damus/issues/1718
Related: https://github.com/damus-io/damus/issues/856
Lighting Address: fishcharlie@strike.me

Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
Charlie Fish 2024-01-17 18:17:36 -07:00 committed by William Casarin
parent f13267aeb2
commit 068b89d087
7 changed files with 323 additions and 5 deletions

View File

@ -424,9 +424,13 @@
B57B4C622B312BD700A232C0 /* ReconnectRelaysNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */; }; B57B4C622B312BD700A232C0 /* ReconnectRelaysNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */; };
B57B4C642B312BFA00A232C0 /* RelayAuthenticationDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */; }; B57B4C642B312BFA00A232C0 /* RelayAuthenticationDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */; };
B57B4C662B312C3700A232C0 /* NostrAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C652B312C3700A232C0 /* NostrAuth.swift */; }; B57B4C662B312C3700A232C0 /* NostrAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57B4C652B312C3700A232C0 /* NostrAuth.swift */; };
B5A75C2A2B546D94007AFBC0 /* MuteItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */; };
B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B4D1422B37D47600844320 /* NdbExtensions.swift */; }; B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B4D1422B37D47600844320 /* NdbExtensions.swift */; };
BA0F0A6F2B36207E001641B2 /* CameraMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */; }; BA0F0A6F2B36207E001641B2 /* CameraMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */; };
BA10192F2B449556009C57DA /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA10192E2B449556009C57DA /* CameraPreview.swift */; }; BA10192F2B449556009C57DA /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA10192E2B449556009C57DA /* CameraPreview.swift */; };
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
B5C60C212B530D5600C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
B5C60C232B532A8700C5ECA7 /* DamusDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */; };
BA37598A2ABCCDE40018D73B /* ImageResizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759892ABCCDE30018D73B /* ImageResizer.swift */; }; BA37598A2ABCCDE40018D73B /* ImageResizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759892ABCCDE30018D73B /* ImageResizer.swift */; };
BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */; }; BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */; };
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */; }; BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */; };
@ -1318,9 +1322,12 @@
B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReconnectRelaysNotify.swift; sourceTree = "<group>"; }; B57B4C612B312BD700A232C0 /* ReconnectRelaysNotify.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReconnectRelaysNotify.swift; sourceTree = "<group>"; };
B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelayAuthenticationDetail.swift; sourceTree = "<group>"; }; B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelayAuthenticationDetail.swift; sourceTree = "<group>"; };
B57B4C652B312C3700A232C0 /* NostrAuth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NostrAuth.swift; sourceTree = "<group>"; }; B57B4C652B312C3700A232C0 /* NostrAuth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NostrAuth.swift; sourceTree = "<group>"; };
B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItemTests.swift; sourceTree = "<group>"; usesTabs = 0; };
B5B4D1422B37D47600844320 /* NdbExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbExtensions.swift; sourceTree = "<group>"; usesTabs = 0; }; B5B4D1422B37D47600844320 /* NdbExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbExtensions.swift; sourceTree = "<group>"; usesTabs = 0; };
BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMediaView.swift; sourceTree = "<group>"; }; BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMediaView.swift; sourceTree = "<group>"; };
BA10192E2B449556009C57DA /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; }; BA10192E2B449556009C57DA /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; };
B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItem.swift; sourceTree = "<group>"; usesTabs = 0; };
B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusDuration.swift; sourceTree = "<group>"; usesTabs = 0; };
BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; }; BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; };
BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCaptureProcessor.swift; sourceTree = "<group>"; }; BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCaptureProcessor.swift; sourceTree = "<group>"; };
BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCaptureProcessor.swift; sourceTree = "<group>"; }; BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCaptureProcessor.swift; sourceTree = "<group>"; };
@ -1591,6 +1598,7 @@
D7EDED1D2B11797D0018B19C /* LongformEvent.swift */, D7EDED1D2B11797D0018B19C /* LongformEvent.swift */,
D7EDED322B12ACAE0018B19C /* DamusUserDefaults.swift */, D7EDED322B12ACAE0018B19C /* DamusUserDefaults.swift */,
D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */, D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */,
B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2294,6 +2302,7 @@
4CC14FED2A73FCBB007AEB17 /* Ids */, 4CC14FED2A73FCBB007AEB17 /* Ids */,
7527271D2A93FF0100214108 /* Block.swift */, 7527271D2A93FF0100214108 /* Block.swift */,
D798D21D2B0858BB00234419 /* MigratedTypes.swift */, D798D21D2B0858BB00234419 /* MigratedTypes.swift */,
B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */,
); );
path = Types; path = Types;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2680,6 +2689,7 @@
children = ( children = (
F944F56D29EA9CCC0067B3BF /* DamusParseContentTests.swift */, F944F56D29EA9CCC0067B3BF /* DamusParseContentTests.swift */,
75AD872A2AA23A460085EF2C /* Block+Tests.swift */, 75AD872A2AA23A460085EF2C /* Block+Tests.swift */,
B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2943,6 +2953,7 @@
ADFE73552AD4793100EC7326 /* QRScanNSECView.swift in Sources */, ADFE73552AD4793100EC7326 /* QRScanNSECView.swift in Sources */,
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */, 4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */,
5CF72FC229B9142F00124A13 /* ShareAction.swift in Sources */, 5CF72FC229B9142F00124A13 /* ShareAction.swift in Sources */,
B5C60C232B532A8700C5ECA7 /* DamusDuration.swift in Sources */,
4C32B9522A9AD44700DC3548 /* Message.swift in Sources */, 4C32B9522A9AD44700DC3548 /* Message.swift in Sources */,
4C8D1A6C29F1DFC200ACDF75 /* FriendIcon.swift in Sources */, 4C8D1A6C29F1DFC200ACDF75 /* FriendIcon.swift in Sources */,
4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */, 4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */,
@ -3050,6 +3061,7 @@
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */, 4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */, 4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */, BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */,
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */,
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */, 4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */, 4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
D74AAFC22B153395006CF0F4 /* HeadlessDamusState.swift in Sources */, D74AAFC22B153395006CF0F4 /* HeadlessDamusState.swift in Sources */,
@ -3387,6 +3399,7 @@
B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */, B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */,
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */, 3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */,
D72A2D072AD9C1FB002AFF62 /* MockProfiles.swift in Sources */, D72A2D072AD9C1FB002AFF62 /* MockProfiles.swift in Sources */,
B5A75C2A2B546D94007AFBC0 /* MuteItemTests.swift in Sources */,
4C4F14A72A2A61A30045A0B9 /* NostrScriptTests.swift in Sources */, 4C4F14A72A2A61A30045A0B9 /* NostrScriptTests.swift in Sources */,
D78525252A7B2EA4002FA637 /* NoteContentViewTests.swift in Sources */, D78525252A7B2EA4002FA637 /* NoteContentViewTests.swift in Sources */,
4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */, 4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */,
@ -3548,6 +3561,7 @@
D7CB5D472B11718700AD4105 /* Wallet.swift in Sources */, D7CB5D472B11718700AD4105 /* Wallet.swift in Sources */,
D7CE1B412B0BE719002EDAD4 /* FlatBuffersUtils.swift in Sources */, D7CE1B412B0BE719002EDAD4 /* FlatBuffersUtils.swift in Sources */,
D7CB5D482B11719300AD4105 /* Profiles.swift in Sources */, D7CB5D482B11719300AD4105 /* Profiles.swift in Sources */,
B5C60C212B530D5600C5ECA7 /* MuteItem.swift in Sources */,
D798D2262B085C4200234419 /* Bech32.swift in Sources */, D798D2262B085C4200234419 /* Bech32.swift in Sources */,
D7CE1B482B0BE719002EDAD4 /* Message.swift in Sources */, D7CE1B482B0BE719002EDAD4 /* Message.swift in Sources */,
D7CB5D462B11703D00AD4105 /* Notify.swift in Sources */, D7CB5D462B11703D00AD4105 /* Notify.swift in Sources */,

View File

@ -1116,7 +1116,7 @@ func on_open_url(state: DamusState, url: URL, result: @escaping (OpenResult?) ->
result(.event(ev)) result(.event(ev))
} }
case .hashtag(let ht): case .hashtag(let ht):
result(.filter(.filter_hashtag([ht.string()]))) result(.filter(.filter_hashtag([ht.hashtag])))
case .param, .quote: case .param, .quote:
// doesn't really make sense here // doesn't really make sense here
break break

View File

@ -109,7 +109,7 @@ func is_already_following(contacts: NostrEvent, follow: FollowRef) -> Bool {
return contacts.references.contains { ref in return contacts.references.contains { ref in
switch (ref, follow) { switch (ref, follow) {
case let (.hashtag(ht), .hashtag(follow_ht)): case let (.hashtag(ht), .hashtag(follow_ht)):
return ht.string() == follow_ht return ht.hashtag == follow_ht
case let (.pubkey(pk), .pubkey(follow_pk)): case let (.pubkey(pk), .pubkey(follow_pk)):
return pk == follow_pk return pk == follow_pk
case (.hashtag, .pubkey), (.pubkey, .hashtag), case (.hashtag, .pubkey), (.pubkey, .hashtag),

208
damus/Models/MuteItem.swift Normal file
View File

@ -0,0 +1,208 @@
//
// MuteItem.swift
// damus
//
// Created by Charlie Fish on 1/13/24.
//
import Foundation
/// Represents an item that is muted.
enum MuteItem: Hashable, Equatable {
/// A user that is muted.
///
/// The associated type is the ``Pubkey`` that is muted. The second associated type is the date that the item should expire at. If no date is supplied, assume the muted item should remain active until it expires.
case user(Pubkey, Date?)
/// A hashtag that is muted.
///
/// The associated type is the hashtag string that is muted. The second associated type is the date that the item should expire at. If no date is supplied, assume the muted item should remain active until it expires.
case hashtag(Hashtag, Date?)
/// A word/phrase that is muted.
///
/// The associated type is the word/phrase that is muted. The second associated type is the date that the item should expire at. If no date is supplied, assume the muted item should remain active until it expires.
case word(String, Date?)
/// A thread that is muted.
///
/// The associated type is the `id` of the note that is muted. The second associated type is the date that the item should expire at. If no date is supplied, assume the muted item should remain active until it expires.
case thread(NoteId, Date?)
func is_expired() -> Bool {
switch self {
case .user(_, let expiration_date):
return expiration_date ?? .distantFuture < Date()
case .hashtag(_, let expiration_date):
return expiration_date ?? .distantFuture < Date()
case .word(_, let expiration_date):
return expiration_date ?? .distantFuture < Date()
case .thread(_, let expiration_date):
return expiration_date ?? .distantFuture < Date()
}
}
static func == (lhs: MuteItem, rhs: MuteItem) -> Bool {
// lhs is the item we want to check (ie. the item the user is attempting to display)
// rhs is the item we want to check against (ie. the item in the mute list)
switch (lhs, rhs) {
case (.user(let lhs_pubkey, _), .user(let rhs_pubkey, let rhs_expiration_date)):
return lhs_pubkey == rhs_pubkey && !rhs.is_expired()
case (.hashtag(let lhs_hashtag, _), .hashtag(let rhs_hashtag, let rhs_expiration_date)):
return lhs_hashtag == rhs_hashtag && !rhs.is_expired()
case (.word(let lhs_word, _), .word(let rhs_word, let rhs_expiration_date)):
return lhs_word == rhs_word && !rhs.is_expired()
case (.thread(let lhs_thread, _), .thread(let rhs_thread, let rhs_expiration_date)):
return lhs_thread == rhs_thread && !rhs.is_expired()
default:
return false
}
}
private var refTags: [String] {
switch self {
case .user(let pubkey, _):
return RefId.pubkey(pubkey).tag
case .hashtag(let hashtag, _):
return RefId.hashtag(hashtag).tag
case .word(let string, _):
return ["word", string]
case .thread(let noteId, _):
return RefId.event(noteId).tag
}
}
var tag: [String] {
var tag = self.refTags
switch self {
case .user(_, let date):
if let date {
tag.append("\(Int(date.timeIntervalSince1970))")
}
case .hashtag(_, let date):
if let date {
tag.append("\(Int(date.timeIntervalSince1970))")
}
case .word(_, let date):
if let date {
tag.append("\(Int(date.timeIntervalSince1970))")
}
case .thread(_, let date):
if let date {
tag.append("\(Int(date.timeIntervalSince1970))")
}
}
return tag
}
var title: String {
switch self {
case .user:
return "user"
case .hashtag:
return "hashtag"
case .word:
return "word"
case .thread:
return "thread"
}
}
init?(_ tag: [String]) {
guard let tag_id = tag.first else { return nil }
guard let tag_content = tag[safe: 1] else { return nil }
let tag_expiration_date: Date? = {
if let tag_expiration_string: String = tag[safe: 2],
let tag_expiration_number: TimeInterval = Double(tag_expiration_string) {
return Date(timeIntervalSince1970: tag_expiration_number)
} else {
return nil
}
}()
switch tag_id {
case "p":
guard let pubkey = Pubkey(hex: tag_content) else { return nil }
self = MuteItem.user(pubkey, tag_expiration_date)
break
case "t":
self = MuteItem.hashtag(Hashtag(hashtag: tag_content), tag_expiration_date)
break
case "word":
self = MuteItem.word(tag_content, tag_expiration_date)
break
case "thread":
guard let note_id = NoteId(hex: tag_content) else { return nil }
self = MuteItem.thread(note_id, tag_expiration_date)
break
default:
return nil
}
}
}
extension Collection where Element == MuteItem {
/// Check if an event is muted given a collection of ``MutedItem``.
///
/// - Parameter ev: The ``NostrEvent`` that you want to check the muted reason for.
/// - Returns: The ``MuteItem`` that matched the event. Or `nil` if the event is not muted.
func event_muted_reason(_ ev: NostrEvent) -> MuteItem? {
return self.first { muted_item in
switch muted_item {
case .user(let pubkey, let expiration_date):
return pubkey == ev.pubkey && !muted_item.is_expired()
case .hashtag(let hashtag, let expiration_date):
return ev.referenced_hashtags.contains(hashtag) && !muted_item.is_expired()
case .word(let word, let expiration_date):
return ev.content.lowercased().contains(word.lowercased()) && !muted_item.is_expired()
case .thread(let note_id, let expiration_date):
return ev.referenced_ids.contains(note_id) && !muted_item.is_expired()
}
}
}
var users: [Pubkey] {
return self.compactMap { muted_item in
if case .user(let pubkey, _) = muted_item,
!muted_item.is_expired() {
return pubkey
} else {
return nil
}
}
}
var hashtags: [Hashtag] {
return self.compactMap { muted_item in
if case .hashtag(let hashtag, _) = muted_item,
!muted_item.is_expired() {
return hashtag
} else {
return nil
}
}
}
var words: [String] {
return self.compactMap { muted_item in
if case .word(let str, _) = muted_item,
!muted_item.is_expired() {
return str
} else {
return nil
}
}
}
var threads: [NoteId] {
return self.compactMap { muted_item in
if case .thread(let note_id, _) = muted_item,
!muted_item.is_expired() {
return note_id
} else {
return nil
}
}
}
}

View File

@ -119,7 +119,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case event(NoteId) case event(NoteId)
case pubkey(Pubkey) case pubkey(Pubkey)
case quote(QuoteId) case quote(QuoteId)
case hashtag(TagElem) case hashtag(Hashtag)
case param(TagElem) case param(TagElem)
case naddr(NAddr) case naddr(NAddr)
@ -155,7 +155,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case .event(let noteId): return noteId.hex() case .event(let noteId): return noteId.hex()
case .pubkey(let pubkey): return pubkey.hex() case .pubkey(let pubkey): return pubkey.hex()
case .quote(let quote): return quote.hex() case .quote(let quote): return quote.hex()
case .hashtag(let string): return string.string() case .hashtag(let string): return string.hashtag
case .param(let string): return string.string() case .param(let string): return string.string()
case .naddr(let naddr): case .naddr(let naddr):
return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier
@ -176,7 +176,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
case .e: return t1.id().map({ .event(NoteId($0)) }) case .e: return t1.id().map({ .event(NoteId($0)) })
case .p: return t1.id().map({ .pubkey(Pubkey($0)) }) case .p: return t1.id().map({ .pubkey(Pubkey($0)) })
case .q: return t1.id().map({ .quote(QuoteId($0)) }) case .q: return t1.id().map({ .quote(QuoteId($0)) })
case .t: return .hashtag(t1) case .t: return .hashtag(Hashtag(hashtag: t1.string()))
case .d: return .param(t1) case .d: return .param(t1)
case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0)) case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0))
} }

View File

@ -0,0 +1,38 @@
//
// DamusDuration.swift
// damus
//
// Created by Charlie Fish on 1/13/24.
//
import Foundation
enum DamusDuration: CaseIterable {
case day
case week
case month
var title: String {
switch self {
case .day:
return NSLocalizedString("24 hours", comment: "A duration of 24 hours/1 day to be shown to the user. Most likely in the context of how long they want to mute a piece of content for.")
case .week:
return NSLocalizedString("1 week", comment: "A duration of 1 week to be shown to the user. Most likely in the context of how long they want to mute a piece of content for.")
case .month:
return NSLocalizedString("1 month", comment: "A duration of 1 month to be shown to the user. Most likely in the context of how long they want to mute a piece of content for.")
}
}
var date_from_now: Date? {
let current_date = Date()
switch self {
case .day:
return Calendar.current.date(byAdding: .day, value: 1, to: current_date)
case .week:
return Calendar.current.date(byAdding: .day, value: 7, to: current_date)
case .month:
return Calendar.current.date(byAdding: .month, value: 1, to: current_date)
}
}
}

View File

@ -0,0 +1,58 @@
//
// MuteItemTests.swift
// damusTests
//
// Created by Charlie Fish on 1/14/24.
//
import XCTest
@testable import damus
class MuteItemTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
// MARK: - `is_expired`
func test_hashtag_is_expired() throws {
XCTAssertTrue(MuteItem.hashtag(Hashtag(hashtag: "test"), Date(timeIntervalSince1970: 0)).is_expired())
XCTAssertTrue(MuteItem.hashtag(Hashtag(hashtag: "test"), .distantPast).is_expired())
XCTAssertFalse(MuteItem.hashtag(Hashtag(hashtag: "test"), .distantFuture).is_expired())
}
func test_user_is_expired() throws {
XCTAssertTrue(MuteItem.user(test_pubkey, Date(timeIntervalSince1970: 0)).is_expired())
XCTAssertTrue(MuteItem.user(test_pubkey, .distantPast).is_expired())
XCTAssertFalse(MuteItem.user(test_pubkey, .distantFuture).is_expired())
}
func test_word_is_expired() throws {
XCTAssertTrue(MuteItem.word("test", Date(timeIntervalSince1970: 0)).is_expired())
XCTAssertTrue(MuteItem.word("test", .distantPast).is_expired())
XCTAssertFalse(MuteItem.word("test", .distantFuture).is_expired())
}
func test_thread_is_expired() throws {
XCTAssertTrue(MuteItem.thread(test_note.id, Date(timeIntervalSince1970: 0)).is_expired())
XCTAssertTrue(MuteItem.thread(test_note.id, .distantPast).is_expired())
XCTAssertFalse(MuteItem.thread(test_note.id, .distantFuture).is_expired())
}
// MARK: - `tag`
func test_hashtag_tag() throws {
XCTAssertEqual(MuteItem.hashtag(Hashtag(hashtag: "test"), nil).tag, ["t", "test"])
XCTAssertEqual(MuteItem.hashtag(Hashtag(hashtag: "test"), Date(timeIntervalSince1970: 1704067200)).tag, ["t", "test", "1704067200"])
}
func test_user_tag() throws {
XCTAssertEqual(MuteItem.user(test_pubkey, Date(timeIntervalSince1970: 1704067200)).tag, ["p", test_pubkey.hex(), "1704067200"])
}
func test_word_tag() throws {
XCTAssertEqual(MuteItem.word("test", Date(timeIntervalSince1970: 1704067200)).tag, ["word", "test", "1704067200"])
}
func test_thread_tag() throws {
XCTAssertEqual(MuteItem.thread(test_note.id, Date(timeIntervalSince1970: 1704067200)).tag, ["e", test_note.id.hex(), "1704067200"])
}
}