Merge branch 'master' into exp-backoff

This commit is contained in:
Bryan Montz
2023-02-27 06:23:38 -06:00
127 changed files with 3337 additions and 849 deletions

View File

@@ -1,3 +1,28 @@
## [1.1.0-9] - 2023-02-26
### Added
- Customized zaps (William Casarin)
- Add new Notifications View (William Casarin)
- Bookmarking (Joel Klabo)
### Changed
- No more inline npubs when tagging users (Swift)
### Fixed
- Fix alignment of side menu labels (Joel Klabo)
- Fix duplicated participants in reply-to view (Joel Klabo)
- Load missing profiles in Zaps view (William Casarin)
- Fix memory leak with inline videos (William Casarin)
- Eliminate popping when scrolling (William Casarin)
[1.1.0-9]: https://github.com/damus-io/damus/releases/tag/v1.1.0-9
## [1.1.0-3] - 2023-02-20 ## [1.1.0-3] - 2023-02-20
### Added ### Added

View File

@@ -11,6 +11,11 @@
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; }; 3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; };
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; }; 3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; }; 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
3A3040ED29A5CB86008A0F29 /* ReplyDescriptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040EC29A5CB86008A0F29 /* ReplyDescriptionTests.swift */; };
3A3040EF29A8FEE9008A0F29 /* EventDetailBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040EE29A8FEE9008A0F29 /* EventDetailBarTests.swift */; };
3A3040F129A8FF97008A0F29 /* LocalizationUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F029A8FF97008A0F29 /* LocalizationUtil.swift */; };
3A3040F329A91366008A0F29 /* ProfileViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F229A91366008A0F29 /* ProfileViewTests.swift */; };
3A30410129AB12AA008A0F29 /* EventGroupViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30410029AB12AA008A0F29 /* EventGroupViewTests.swift */; };
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; }; 3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; }; 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; }; 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
@@ -43,6 +48,11 @@
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8B28398BC6008A31F1 /* Keys.swift */; }; 4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8B28398BC6008A31F1 /* Keys.swift */; };
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */; }; 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */; };
4C2CDDF7299D4A5E00879FD5 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */; }; 4C2CDDF7299D4A5E00879FD5 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */; };
4C30AC7229A5677A00E2BD5A /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7129A5677A00E2BD5A /* NotificationsView.swift */; };
4C30AC7429A5680900E2BD5A /* EventGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7329A5680900E2BD5A /* EventGroupView.swift */; };
4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7529A5770900E2BD5A /* NotificationItemView.swift */; };
4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7729A577AB00E2BD5A /* EventCache.swift */; };
4C30AC8029A6A53F00E2BD5A /* ProfilePicturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7F29A6A53F00E2BD5A /* ProfilePicturesView.swift */; };
4C363A8428233689006E126D /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8328233689006E126D /* Parser.swift */; }; 4C363A8428233689006E126D /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8328233689006E126D /* Parser.swift */; };
4C363A8828236948006E126D /* BlocksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8728236948006E126D /* BlocksView.swift */; }; 4C363A8828236948006E126D /* BlocksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8728236948006E126D /* BlocksView.swift */; };
4C363A8A28236B57006E126D /* MentionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8928236B57006E126D /* MentionView.swift */; }; 4C363A8A28236B57006E126D /* MentionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8928236B57006E126D /* MentionView.swift */; };
@@ -93,6 +103,9 @@
4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EA67E28FFC01D00C48A62 /* InvoiceView.swift */; }; 4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EA67E28FFC01D00C48A62 /* InvoiceView.swift */; };
4C42812C298C848200DBF26F /* TranslateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C42812B298C848200DBF26F /* TranslateView.swift */; }; 4C42812C298C848200DBF26F /* TranslateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C42812B298C848200DBF26F /* TranslateView.swift */; };
4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C477C9D282C3A4800033AA3 /* TipCounter.swift */; }; 4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C477C9D282C3A4800033AA3 /* TipCounter.swift */; };
4C54AA0729A540BA003E4487 /* NotificationsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C54AA0629A540BA003E4487 /* NotificationsModel.swift */; };
4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C54AA0929A55429003E4487 /* EventGroup.swift */; };
4C54AA0C29A5543C003E4487 /* ZapGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C54AA0B29A5543C003E4487 /* ZapGroup.swift */; };
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */; }; 4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */; };
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C7E69284EDE2E00A22DF5 /* SearchResultsView.swift */; }; 4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C7E69284EDE2E00A22DF5 /* SearchResultsView.swift */; };
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5F9113283D694D0052CD1C /* FollowTarget.swift */; }; 4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5F9113283D694D0052CD1C /* FollowTarget.swift */; };
@@ -122,6 +135,8 @@
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */; }; 4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */; };
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; }; 4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; };
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */; }; 4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */; };
4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */; };
4C9F18E429ABDE6D008C55EC /* MaybeAnonPfpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */; };
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; }; 4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; };
4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AC298851D000060CEA /* AccountDeletion.swift */; }; 4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AC298851D000060CEA /* AccountDeletion.swift */; };
4CAAD8B029888AD200060CEA /* RelayConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */; }; 4CAAD8B029888AD200060CEA /* RelayConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */; };
@@ -216,6 +231,7 @@
7C95CAEE299DCEF1009DCB67 /* KFOptionSetter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */; }; 7C95CAEE299DCEF1009DCB67 /* KFOptionSetter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */; };
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF6316299FEFE5005D382A /* SelectableText.swift */; }; 7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF6316299FEFE5005D382A /* SelectableText.swift */; };
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9609F057296E220800069BF3 /* BannerImageView.swift */; }; 9609F058296E220800069BF3 /* BannerImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9609F057296E220800069BF3 /* BannerImageView.swift */; };
9C83F89329A937B900136C08 /* TextViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83F89229A937B900136C08 /* TextViewWrapper.swift */; };
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; }; BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; }; BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; }; DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; };
@@ -258,6 +274,18 @@
3A25EF142992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el-GR"; path = "el-GR.lproj/Localizable.strings"; sourceTree = "<group>"; }; 3A25EF142992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el-GR"; path = "el-GR.lproj/Localizable.strings"; sourceTree = "<group>"; };
3A25EF152992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "el-GR"; path = "el-GR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; }; 3A25EF152992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "el-GR"; path = "el-GR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
3A2B8B0A296A8982009CC16D /* en-US */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "en-US"; path = "en-US.lproj/Localizable.stringsdict"; sourceTree = "<group>"; }; 3A2B8B0A296A8982009CC16D /* en-US */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "en-US"; path = "en-US.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
3A3040EC29A5CB86008A0F29 /* ReplyDescriptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyDescriptionTests.swift; sourceTree = "<group>"; };
3A3040EE29A8FEE9008A0F29 /* EventDetailBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailBarTests.swift; sourceTree = "<group>"; };
3A3040F029A8FF97008A0F29 /* LocalizationUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationUtil.swift; sourceTree = "<group>"; };
3A3040F229A91366008A0F29 /* ProfileViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewTests.swift; sourceTree = "<group>"; };
3A3040F929A91ED6008A0F29 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3A3040FA29A91EFC008A0F29 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Localizable.strings"; sourceTree = "<group>"; };
3A3040FB29A91F03008A0F29 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-HK"; path = "zh-HK.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
3A3040FC29A91F31008A0F29 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = "zh-TW.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3A3040FD29A91F31008A0F29 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-TW"; path = "zh-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
3A3040FE29A91F31008A0F29 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = "zh-TW.lproj/Localizable.strings"; sourceTree = "<group>"; };
3A3040FF29AB02D1008A0F29 /* en-US */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-US"; path = "en-US.lproj/Localizable.strings"; sourceTree = "<group>"; };
3A30410029AB12AA008A0F29 /* EventGroupViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGroupViewTests.swift; sourceTree = "<group>"; };
3A41E559299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 3A41E559299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3A41E55A299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; }; 3A41E55A299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
3A41E55B299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = id; path = id.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; 3A41E55B299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = id; path = id.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -331,6 +359,11 @@
4C285C8B28398BC6008A31F1 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; }; 4C285C8B28398BC6008A31F1 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; };
4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveKeysView.swift; sourceTree = "<group>"; }; 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveKeysView.swift; sourceTree = "<group>"; };
4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; }; 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; };
4C30AC7129A5677A00E2BD5A /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
4C30AC7329A5680900E2BD5A /* EventGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGroupView.swift; sourceTree = "<group>"; };
4C30AC7529A5770900E2BD5A /* NotificationItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemView.swift; sourceTree = "<group>"; };
4C30AC7729A577AB00E2BD5A /* EventCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCache.swift; sourceTree = "<group>"; };
4C30AC7F29A6A53F00E2BD5A /* ProfilePicturesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePicturesView.swift; sourceTree = "<group>"; };
4C363A8328233689006E126D /* Parser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; }; 4C363A8328233689006E126D /* Parser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; };
4C363A8728236948006E126D /* BlocksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocksView.swift; sourceTree = "<group>"; }; 4C363A8728236948006E126D /* BlocksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocksView.swift; sourceTree = "<group>"; };
4C363A8928236B57006E126D /* MentionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionView.swift; sourceTree = "<group>"; }; 4C363A8928236B57006E126D /* MentionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionView.swift; sourceTree = "<group>"; };
@@ -411,6 +444,9 @@
4C42812B298C848200DBF26F /* TranslateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslateView.swift; sourceTree = "<group>"; }; 4C42812B298C848200DBF26F /* TranslateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslateView.swift; sourceTree = "<group>"; };
4C477C9D282C3A4800033AA3 /* TipCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TipCounter.swift; sourceTree = "<group>"; }; 4C477C9D282C3A4800033AA3 /* TipCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TipCounter.swift; sourceTree = "<group>"; };
4C4A3A5A288A1B2200453788 /* damus.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = damus.entitlements; sourceTree = "<group>"; }; 4C4A3A5A288A1B2200453788 /* damus.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = damus.entitlements; sourceTree = "<group>"; };
4C54AA0629A540BA003E4487 /* NotificationsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsModel.swift; sourceTree = "<group>"; };
4C54AA0929A55429003E4487 /* EventGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGroup.swift; sourceTree = "<group>"; };
4C54AA0B29A5543C003E4487 /* ZapGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZapGroup.swift; sourceTree = "<group>"; };
4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHomeModel.swift; sourceTree = "<group>"; }; 4C5C7E67284ED36500A22DF5 /* SearchHomeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHomeModel.swift; sourceTree = "<group>"; };
4C5C7E69284EDE2E00A22DF5 /* SearchResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsView.swift; sourceTree = "<group>"; }; 4C5C7E69284EDE2E00A22DF5 /* SearchResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsView.swift; sourceTree = "<group>"; };
4C5F9113283D694D0052CD1C /* FollowTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowTarget.swift; sourceTree = "<group>"; }; 4C5F9113283D694D0052CD1C /* FollowTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowTarget.swift; sourceTree = "<group>"; };
@@ -440,6 +476,8 @@
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; }; 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; }; 4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; };
4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomMetadata.swift; sourceTree = "<group>"; }; 4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomMetadata.swift; sourceTree = "<group>"; };
4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeZapView.swift; sourceTree = "<group>"; };
4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaybeAnonPfpView.swift; sourceTree = "<group>"; };
4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; }; 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
4CAAD8AC298851D000060CEA /* AccountDeletion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDeletion.swift; sourceTree = "<group>"; }; 4CAAD8AC298851D000060CEA /* AccountDeletion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDeletion.swift; sourceTree = "<group>"; };
4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConfigView.swift; sourceTree = "<group>"; }; 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConfigView.swift; sourceTree = "<group>"; };
@@ -536,6 +574,7 @@
7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KFOptionSetter+.swift"; sourceTree = "<group>"; }; 7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KFOptionSetter+.swift"; sourceTree = "<group>"; };
7CFF6316299FEFE5005D382A /* SelectableText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableText.swift; sourceTree = "<group>"; }; 7CFF6316299FEFE5005D382A /* SelectableText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableText.swift; sourceTree = "<group>"; };
9609F057296E220800069BF3 /* BannerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerImageView.swift; sourceTree = "<group>"; }; 9609F057296E220800069BF3 /* BannerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerImageView.swift; sourceTree = "<group>"; };
9C83F89229A937B900136C08 /* TextViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewWrapper.swift; sourceTree = "<group>"; };
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; }; BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; }; BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; }; DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; };
@@ -651,6 +690,7 @@
4C0A3F8D280F63FF000448DE /* Models */ = { 4C0A3F8D280F63FF000448DE /* Models */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4C54AA0829A55416003E4487 /* Notifications */,
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */, 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */,
4C0A3F8E280F640A000448DE /* ThreadModel.swift */, 4C0A3F8E280F640A000448DE /* ThreadModel.swift */,
4C0A3F92280F66F5000448DE /* ReplyMap.swift */, 4C0A3F92280F66F5000448DE /* ReplyMap.swift */,
@@ -690,13 +730,35 @@
3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */, 3AAA95CB298E07E900F3D526 /* DeepLPlan.swift */,
4CE8795A2996C47A00F758CC /* ZapsModel.swift */, 4CE8795A2996C47A00F758CC /* ZapsModel.swift */,
3AA59D1C2999B0400061C48E /* DraftsModel.swift */, 3AA59D1C2999B0400061C48E /* DraftsModel.swift */,
4C54AA0629A540BA003E4487 /* NotificationsModel.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4C30AC7029A5676F00E2BD5A /* Notifications */ = {
isa = PBXGroup;
children = (
4C30AC7129A5677A00E2BD5A /* NotificationsView.swift */,
4C30AC7329A5680900E2BD5A /* EventGroupView.swift */,
4C30AC7529A5770900E2BD5A /* NotificationItemView.swift */,
4C30AC7F29A6A53F00E2BD5A /* ProfilePicturesView.swift */,
);
path = Notifications;
sourceTree = "<group>";
};
4C54AA0829A55416003E4487 /* Notifications */ = {
isa = PBXGroup;
children = (
4C54AA0929A55429003E4487 /* EventGroup.swift */,
4C54AA0B29A5543C003E4487 /* ZapGroup.swift */,
);
path = Notifications;
sourceTree = "<group>";
};
4C75EFA227FA576C0006080F /* Views */ = { 4C75EFA227FA576C0006080F /* Views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4C30AC7029A5676F00E2BD5A /* Notifications */,
4CE0E2B029A3DF4700DB4CA2 /* Timeline */, 4CE0E2B029A3DF4700DB4CA2 /* Timeline */,
4CE879562996C44A00F758CC /* Zaps */, 4CE879562996C44A00F758CC /* Zaps */,
4CB9D4A52992D01900A9A7E4 /* Profile */, 4CB9D4A52992D01900A9A7E4 /* Profile */,
@@ -729,6 +791,7 @@
4C363A8D28236FE4006E126D /* NoteContentView.swift */, 4C363A8D28236FE4006E126D /* NoteContentView.swift */,
4C75EFAC28049CFB0006080F /* PostButton.swift */, 4C75EFAC28049CFB0006080F /* PostButton.swift */,
4C75EFA327FA577B0006080F /* PostView.swift */, 4C75EFA327FA577B0006080F /* PostView.swift */,
9C83F89229A937B900136C08 /* TextViewWrapper.swift */,
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */, 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */,
4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */, 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */,
4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */, 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */,
@@ -812,6 +875,8 @@
4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */, 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */,
7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */, 7C95CAED299DCEF1009DCB67 /* KFOptionSetter+.swift */,
4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */, 4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */,
3A3040F029A8FF97008A0F29 /* LocalizationUtil.swift */,
4C30AC7729A577AB00E2BD5A /* EventCache.swift */,
); );
path = Util; path = Util;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -853,6 +918,7 @@
children = ( children = (
4CB9D4A62992D02B00A9A7E4 /* ProfileNameView.swift */, 4CB9D4A62992D02B00A9A7E4 /* ProfileNameView.swift */,
4CB9D4A82992D2F400A9A7E4 /* FollowsYou.swift */, 4CB9D4A82992D2F400A9A7E4 /* FollowsYou.swift */,
4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */,
); );
path = Profile; path = Profile;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -974,6 +1040,10 @@
4CF0ABDB2981A19E00D66079 /* ListTests.swift */, 4CF0ABDB2981A19E00D66079 /* ListTests.swift */,
4CB883A9297612FF00DC99E7 /* ZapTests.swift */, 4CB883A9297612FF00DC99E7 /* ZapTests.swift */,
4CB883AD2976FA9300DC99E7 /* FormatTests.swift */, 4CB883AD2976FA9300DC99E7 /* FormatTests.swift */,
3A3040EC29A5CB86008A0F29 /* ReplyDescriptionTests.swift */,
3A3040EE29A8FEE9008A0F29 /* EventDetailBarTests.swift */,
3A3040F229A91366008A0F29 /* ProfileViewTests.swift */,
3A30410029AB12AA008A0F29 /* EventGroupViewTests.swift */,
); );
path = damusTests; path = damusTests;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1008,6 +1078,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4CE879572996C45300F758CC /* ZapsView.swift */, 4CE879572996C45300F758CC /* ZapsView.swift */,
4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */,
); );
path = Zaps; path = Zaps;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1163,6 +1234,8 @@
id, id,
cs, cs,
ru, ru,
"zh-HK",
"zh-TW",
); );
mainGroup = 4CE6DEDA27F7A08100C66700; mainGroup = 4CE6DEDA27F7A08100C66700;
packageReferences = ( packageReferences = (
@@ -1219,6 +1292,7 @@
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */, 4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */,
4C363A8A28236B57006E126D /* MentionView.swift in Sources */, 4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */, 4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
4C30AC7829A577AB00E2BD5A /* EventCache.swift in Sources */,
4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */, 4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
4C216F34286F5ACD00040376 /* DMView.swift in Sources */, 4C216F34286F5ACD00040376 /* DMView.swift in Sources */,
4C3EA64428FF558100C48A62 /* sha256.c in Sources */, 4C3EA64428FF558100C48A62 /* sha256.c in Sources */,
@@ -1231,6 +1305,7 @@
4CE8794C2995B59E00F758CC /* RelayMetadatas.swift in Sources */, 4CE8794C2995B59E00F758CC /* RelayMetadatas.swift in Sources */,
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */, 4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */, 4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */,
4C54AA0C29A5543C003E4487 /* ZapGroup.swift in Sources */,
4C75EFB728049D990006080F /* RelayPool.swift in Sources */, 4C75EFB728049D990006080F /* RelayPool.swift in Sources */,
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */, 4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */,
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */, 4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */,
@@ -1242,6 +1317,7 @@
4C363AA228296A7E006E126D /* SearchView.swift in Sources */, 4C363AA228296A7E006E126D /* SearchView.swift in Sources */,
4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */, 4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */,
4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */, 4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */,
4C9F18E429ABDE6D008C55EC /* MaybeAnonPfpView.swift in Sources */,
4C75EFB92804A2740006080F /* EventView.swift in Sources */, 4C75EFB92804A2740006080F /* EventView.swift in Sources */,
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */, 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */,
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */, F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
@@ -1273,6 +1349,7 @@
4C649844285A952100EAE2B3 /* LocalUserConfig.swift in Sources */, 4C649844285A952100EAE2B3 /* LocalUserConfig.swift in Sources */,
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */, 4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */, 4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */,
4C363A8428233689006E126D /* Parser.swift in Sources */, 4C363A8428233689006E126D /* Parser.swift in Sources */,
3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */, 3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */,
4CE4F9E328528C5200C00DD9 /* AddRelayView.swift in Sources */, 4CE4F9E328528C5200C00DD9 /* AddRelayView.swift in Sources */,
@@ -1284,6 +1361,7 @@
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */, E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */,
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */, 4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
4CF0ABE7298444FD00D66079 /* MutedEventView.swift in Sources */, 4CF0ABE7298444FD00D66079 /* MutedEventView.swift in Sources */,
9C83F89329A937B900136C08 /* TextViewWrapper.swift in Sources */,
4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */, 4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */,
4CB883A82975FC1800DC99E7 /* Zaps.swift in Sources */, 4CB883A82975FC1800DC99E7 /* Zaps.swift in Sources */,
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */, 4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
@@ -1292,6 +1370,7 @@
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */, 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */,
F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */, F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */,
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */, 4C285C8228385570008A31F1 /* CarouselView.swift in Sources */,
3A3040F129A8FF97008A0F29 /* LocalizationUtil.swift in Sources */,
F75BA12D29A1855400E10810 /* BookmarksManager.swift in Sources */, F75BA12D29A1855400E10810 /* BookmarksManager.swift in Sources */,
4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */, 4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */,
4CE8794829941DA700F758CC /* RelayFilters.swift in Sources */, 4CE8794829941DA700F758CC /* RelayFilters.swift in Sources */,
@@ -1321,16 +1400,19 @@
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */, 4C285C8C28398BC7008A31F1 /* Keys.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 */,
4C633352283D419F00B1C9C3 /* SignalModel.swift in Sources */, 4C633352283D419F00B1C9C3 /* SignalModel.swift in Sources */,
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */, 9609F058296E220800069BF3 /* BannerImageView.swift in Sources */,
4C363A94282704FA006E126D /* Post.swift in Sources */, 4C363A94282704FA006E126D /* Post.swift in Sources */,
4C216F32286E388800040376 /* DMChatView.swift in Sources */, 4C216F32286E388800040376 /* DMChatView.swift in Sources */,
4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */, 4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */,
4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */,
4C3EA67928FF7ABF00C48A62 /* list.c in Sources */, 4C3EA67928FF7ABF00C48A62 /* list.c in Sources */,
4C64987E286D082C00EAE2B3 /* DirectMessagesModel.swift in Sources */, 4C64987E286D082C00EAE2B3 /* DirectMessagesModel.swift in Sources */,
4CE0E2B629A3ED5500DB4CA2 /* InnerTimelineView.swift in Sources */, 4CE0E2B629A3ED5500DB4CA2 /* InnerTimelineView.swift in Sources */,
4C363A8828236948006E126D /* BlocksView.swift in Sources */, 4C363A8828236948006E126D /* BlocksView.swift in Sources */,
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */, 4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */,
4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */,
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */, 4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */, 4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */,
4C42812C298C848200DBF26F /* TranslateView.swift in Sources */, 4C42812C298C848200DBF26F /* TranslateView.swift in Sources */,
@@ -1351,6 +1433,7 @@
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */, 4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */,
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */, 4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
4CF0ABD82981980C00D66079 /* Lists.swift in Sources */, 4CF0ABD82981980C00D66079 /* Lists.swift in Sources */,
4C30AC8029A6A53F00E2BD5A /* ProfilePicturesView.swift in Sources */,
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */, 4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
7C60CAEF298471A1009C80D6 /* CoreSVG.swift in Sources */, 7C60CAEF298471A1009C80D6 /* CoreSVG.swift in Sources */,
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */, 6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
@@ -1380,6 +1463,7 @@
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */, 4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */,
4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */, 4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */, 7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
4C54AA0729A540BA003E4487 /* NotificationsModel.swift in Sources */,
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */, 4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */,
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */, 4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */,
4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */, 4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */,
@@ -1404,6 +1488,7 @@
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */, 4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */,
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */, 4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */,
4C75EFA427FA577B0006080F /* PostView.swift in Sources */, 4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
4C30AC7229A5677A00E2BD5A /* NotificationsView.swift in Sources */,
4C75EFB528049D790006080F /* Relay.swift in Sources */, 4C75EFB528049D790006080F /* Relay.swift in Sources */,
4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */, 4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */,
4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */, 4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */,
@@ -1419,8 +1504,11 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
3A3040ED29A5CB86008A0F29 /* ReplyDescriptionTests.swift in Sources */,
3A30410129AB12AA008A0F29 /* EventGroupViewTests.swift in Sources */,
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */, 3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */,
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */, DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */,
3A3040EF29A8FEE9008A0F29 /* EventDetailBarTests.swift in Sources */,
4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */, 4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */,
5023E76329AA3627007D3D50 /* RelayPoolTests.swift in Sources */, 5023E76329AA3627007D3D50 /* RelayPoolTests.swift in Sources */,
4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */, 4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */,
@@ -1431,6 +1519,7 @@
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */, 4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */,
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */, 50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */,
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */, 4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */,
3A3040F329A91366008A0F29 /* ProfileViewTests.swift in Sources */,
4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */, 4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -1480,6 +1569,8 @@
3A41E55B299D52BE001FA465 /* id */, 3A41E55B299D52BE001FA465 /* id */,
3A8624DB299E82BE00BD8BE9 /* cs */, 3A8624DB299E82BE00BD8BE9 /* cs */,
3A827A1A299FC69D00C4D171 /* ru */, 3A827A1A299FC69D00C4D171 /* ru */,
3A3040FB29A91F03008A0F29 /* zh-HK */,
3A3040FD29A91F31008A0F29 /* zh-TW */,
); );
name = Localizable.stringsdict; name = Localizable.stringsdict;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1503,6 +1594,8 @@
3A41E559299D52BE001FA465 /* id */, 3A41E559299D52BE001FA465 /* id */,
3A8624D9299E82BE00BD8BE9 /* cs */, 3A8624D9299E82BE00BD8BE9 /* cs */,
3A827A18299FC69D00C4D171 /* ru */, 3A827A18299FC69D00C4D171 /* ru */,
3A3040F929A91ED6008A0F29 /* zh-HK */,
3A3040FC29A91F31008A0F29 /* zh-TW */,
); );
name = InfoPlist.strings; name = InfoPlist.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1526,6 +1619,9 @@
3A41E55A299D52BE001FA465 /* id */, 3A41E55A299D52BE001FA465 /* id */,
3A8624DA299E82BE00BD8BE9 /* cs */, 3A8624DA299E82BE00BD8BE9 /* cs */,
3A827A19299FC69D00C4D171 /* ru */, 3A827A19299FC69D00C4D171 /* ru */,
3A3040FA29A91EFC008A0F29 /* zh-HK */,
3A3040FE29A91F31008A0F29 /* zh-TW */,
3A3040FF29AB02D1008A0F29 /* en-US */,
); );
name = Localizable.strings; name = Localizable.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1661,7 +1757,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D; DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -1703,7 +1799,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D; DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;

View File

@@ -205,6 +205,7 @@ struct ImageCarousel: View {
view.framePreloadCount = 3 view.framePreloadCount = 3
} }
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.cornerRadius(10)
.tabItem { .tabItem {
Text(url.absoluteString) Text(url.absoluteString)
} }
@@ -217,11 +218,11 @@ struct ImageCarousel: View {
} }
} }
} }
.cornerRadius(10)
.fullScreenCover(isPresented: $open_sheet) { .fullScreenCover(isPresented: $open_sheet) {
ImageView(urls: urls) ImageView(urls: urls)
} }
.frame(height: 200) .frame(height: 200)
.clipped()
.onTapGesture { .onTapGesture {
open_sheet = true open_sheet = true
} }

View File

@@ -12,11 +12,7 @@ struct UserView: View {
let pubkey: String let pubkey: String
var body: some View { var body: some View {
let pmodel = ProfileModel(pubkey: pubkey, damus: damus_state) NavigationLink(destination: ProfileView(damus_state: damus_state, pubkey: pubkey)) {
let followers = FollowersModel(damus_state: damus_state, target: pubkey)
let pv = ProfileView(damus_state: damus_state, profile: pmodel, followers: followers)
NavigationLink(destination: pv) {
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles) ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles)
VStack(alignment: .leading) { VStack(alignment: .leading) {

View File

@@ -7,6 +7,22 @@
import SwiftUI import SwiftUI
enum ZappingEventType {
case failed(ZappingError)
case got_zap_invoice(String)
}
enum ZappingError {
case fetching_invoice
case bad_lnurl
}
struct ZappingEvent {
let is_custom: Bool
let type: ZappingEventType
let event: NostrEvent
}
struct ZapButton: View { struct ZapButton: View {
let damus_state: DamusState let damus_state: DamusState
let event: NostrEvent let event: NostrEvent
@@ -19,61 +35,8 @@ struct ZapButton: View {
@State var slider_value: Double = 0.0 @State var slider_value: Double = 0.0
@State var slider_visible: Bool = false @State var slider_visible: Bool = false
@State var showing_select_wallet: Bool = false @State var showing_select_wallet: Bool = false
@State var showing_zap_customizer: Bool = false
func send_zap() { @State var is_charging: Bool = false
guard let privkey = damus_state.keypair.privkey else {
return
}
// Only take the first 10 because reasons
let relays = Array(damus_state.pool.descriptors.prefix(10))
let target = ZapTarget.note(id: event.id, author: event.pubkey)
// TODO: gather comment?
let content = ""
let zapreq = make_zap_request_event(pubkey: damus_state.pubkey, privkey: privkey, content: content, relays: relays, target: target)
zapping = true
Task {
var mpayreq = damus_state.lnurls.lookup(target.pubkey)
if mpayreq == nil {
mpayreq = await fetch_static_payreq(lnurl)
}
guard let payreq = mpayreq else {
// TODO: show error
DispatchQueue.main.async {
zapping = false
}
return
}
DispatchQueue.main.async {
damus_state.lnurls.endpoints[target.pubkey] = payreq
}
let zap_amount = get_default_zap_amount(pubkey: damus_state.pubkey) ?? 1000
guard let inv = await fetch_zap_invoice(payreq, zapreq: zapreq, sats: zap_amount) else {
DispatchQueue.main.async {
zapping = false
}
return
}
DispatchQueue.main.async {
zapping = false
if should_show_wallet_selector(damus_state.pubkey) {
self.invoice = inv
self.showing_select_wallet = true
} else {
open_with_wallet(wallet: get_default_wallet(damus_state.pubkey).model, invoice: inv)
}
}
}
//damus_state.pool.send(.event(zapreq))
}
var zap_img: String { var zap_img: String {
if bar.zapped { if bar.zapped {
@@ -92,6 +55,10 @@ struct ZapButton: View {
return Color.orange return Color.orange
} }
if is_charging {
return Color.yellow
}
if !zapping { if !zapping {
return nil return nil
} }
@@ -101,22 +68,62 @@ struct ZapButton: View {
var body: some View { var body: some View {
HStack(spacing: 4) { HStack(spacing: 4) {
EventActionButton(img: zap_img, col: zap_color) { Image(systemName: zap_img)
if bar.zapped { .foregroundColor(zap_color == nil ? Color.gray : zap_color!)
//notify(.delete, bar.our_tip) .font(.footnote.weight(.medium))
} else if !zapping { .onTapGesture {
send_zap() if bar.zapped {
//notify(.delete, bar.our_tip)
} else if !zapping {
self.showing_zap_customizer = true
//send_zap(damus_state: damus_state, event: event, lnurl: lnurl, is_custom: false)
//self.zapping = true
}
} }
} .onLongPressGesture(minimumDuration: 0, pressing: { is_charing in
.accessibilityLabel(NSLocalizedString("Zap", comment: "Accessibility label for zap button")) self.is_charging = is_charging
}, perform: {
self.showing_zap_customizer = true
})
.accessibilityLabel(NSLocalizedString("Zap", comment: "Accessibility label for zap button"))
Text(String("\(bar.zap_total > 0 ? "\(format_msats_abbrev(bar.zap_total))" : "")")) if bar.zap_total > 0 {
.font(.footnote) Text(verbatim: format_msats_abbrev(bar.zap_total))
.foregroundColor(bar.zapped ? Color.orange : Color.gray) .font(.footnote)
.foregroundColor(bar.zapped ? Color.orange : Color.gray)
}
}
.sheet(isPresented: $showing_zap_customizer) {
CustomizeZapView(state: damus_state, event: event, lnurl: lnurl)
} }
.sheet(isPresented: $showing_select_wallet, onDismiss: {showing_select_wallet = false}) { .sheet(isPresented: $showing_select_wallet, onDismiss: {showing_select_wallet = false}) {
SelectWalletView(showingSelectWallet: $showing_select_wallet, our_pubkey: damus_state.pubkey, invoice: invoice) SelectWalletView(showingSelectWallet: $showing_select_wallet, our_pubkey: damus_state.pubkey, invoice: invoice)
} }
.onReceive(handle_notify(.zapping)) { notif in
let zap_ev = notif.object as! ZappingEvent
guard zap_ev.event.id == self.event.id else {
return
}
guard !zap_ev.is_custom else {
return
}
switch zap_ev.type {
case .failed:
break
case .got_zap_invoice(let inv):
if should_show_wallet_selector(damus_state.pubkey) {
self.invoice = inv
self.showing_select_wallet = true
} else {
open_with_wallet(wallet: get_default_wallet(damus_state.pubkey).model, invoice: inv)
}
}
self.zapping = false
}
} }
} }
@@ -128,3 +135,55 @@ struct ZapButton_Previews: PreviewProvider {
} }
} }
func send_zap(damus_state: DamusState, event: NostrEvent, lnurl: String, is_custom: Bool, comment: String?, amount_sats: Int?, zap_type: ZapType) {
guard let privkey = damus_state.keypair.privkey else {
return
}
// Only take the first 10 because reasons
let relays = Array(damus_state.pool.descriptors.prefix(10))
let target = ZapTarget.note(id: event.id, author: event.pubkey)
let content = comment ?? ""
let zapreq = make_zap_request_event(pubkey: damus_state.pubkey, privkey: privkey, content: content, relays: relays, target: target, is_anon: zap_type == .anon)
Task {
var mpayreq = damus_state.lnurls.lookup(target.pubkey)
if mpayreq == nil {
mpayreq = await fetch_static_payreq(lnurl)
}
guard let payreq = mpayreq else {
// TODO: show error
DispatchQueue.main.async {
let typ = ZappingEventType.failed(.bad_lnurl)
let ev = ZappingEvent(is_custom: is_custom, type: typ, event: event)
notify(.zapping, ev)
}
return
}
DispatchQueue.main.async {
damus_state.lnurls.endpoints[target.pubkey] = payreq
}
let zap_amount = amount_sats ?? get_default_zap_amount(pubkey: damus_state.pubkey) ?? 1000
guard let inv = await fetch_zap_invoice(payreq, zapreq: zapreq, sats: zap_amount, zap_type: zap_type, comment: comment) else {
DispatchQueue.main.async {
let typ = ZappingEventType.failed(.fetching_invoice)
let ev = ZappingEvent(is_custom: is_custom, type: typ, event: event)
notify(.zapping, ev)
}
return
}
DispatchQueue.main.async {
let ev = ZappingEvent(is_custom: is_custom, type: .got_zap_invoice(inv), event: event)
notify(.zapping, ev)
}
}
return
}

View File

@@ -166,7 +166,7 @@ struct ContentView: View {
Text("Universe 🛸", comment: "Toolbar label for the universal view where posts from all connected relay servers appear.") Text("Universe 🛸", comment: "Toolbar label for the universal view where posts from all connected relay servers appear.")
.bold() .bold()
case .none: case .none:
Text("", comment: "Toolbar label for unknown views. This label would be displayed only if a new timeline view is added but a toolbar label was not explicitly assigned to it yet.") Text(verbatim: "")
} }
} }
} }
@@ -192,7 +192,7 @@ struct ContentView: View {
case .notifications: case .notifications:
VStack(spacing: 0) { VStack(spacing: 0) {
Divider() Divider()
TimelineView(events: home.notifications, loading: $home.loading, damus: damus, show_friend_icon: true, filter: { _ in true }) NotificationsView(state: damus, notifications: home.notifications)
} }
case .dms: case .dms:
DirectMessagesView(damus_state: damus_state!) DirectMessagesView(damus_state: damus_state!)
@@ -615,7 +615,8 @@ struct ContentView: View {
settings: UserSettingsStore(), settings: UserSettingsStore(),
relay_filters: relay_filters, relay_filters: relay_filters,
relay_metadata: metadatas, relay_metadata: metadatas,
drafts: Drafts() drafts: Drafts(),
events: EventCache()
) )
home.damus_state = self.damus_state! home.damus_state = self.damus_state!

View File

@@ -24,6 +24,7 @@ struct DamusState {
let relay_filters: RelayFilters let relay_filters: RelayFilters
let relay_metadata: RelayMetadatas let relay_metadata: RelayMetadatas
let drafts: Drafts let drafts: Drafts
let events: EventCache
var pubkey: String { var pubkey: String {
return keypair.pubkey return keypair.pubkey
@@ -33,8 +34,7 @@ struct DamusState {
keypair.privkey != nil keypair.privkey != nil
} }
static var empty: DamusState { static var empty: DamusState {
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts()) return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts(), events: EventCache())
} }
} }

View File

@@ -8,6 +8,6 @@
import Foundation import Foundation
class Drafts: ObservableObject { class Drafts: ObservableObject {
@Published var post: String = "" @Published var post: NSMutableAttributedString = NSMutableAttributedString(string: "")
@Published var replies: [NostrEvent: String] = [:] @Published var replies: [NostrEvent: NSMutableAttributedString] = [:]
} }

View File

@@ -65,7 +65,7 @@ class EventsModel: ObservableObject {
case .notice(_): case .notice(_):
break break
case .eose(_): case .eose(_):
load_profiles(profiles_subid: profiles_id, relay_id: relay_id, events: events, damus_state: state) load_profiles(profiles_subid: profiles_id, relay_id: relay_id, load: .from_events(events), damus_state: state)
} }
} }
} }

View File

@@ -50,22 +50,18 @@ class HomeModel: ObservableObject {
let profiles_subid = UUID().description let profiles_subid = UUID().description
@Published var new_events: NewEventsBits = NewEventsBits() @Published var new_events: NewEventsBits = NewEventsBits()
@Published var notifications: EventHolder @Published var notifications = NotificationsModel()
@Published var dms: DirectMessagesModel @Published var dms: DirectMessagesModel
@Published var events: EventHolder @Published var events = EventHolder()
@Published var loading: Bool = false @Published var loading: Bool = false
@Published var signal: SignalModel = SignalModel() @Published var signal: SignalModel = SignalModel()
init() { init() {
self.events = EventHolder()
self.notifications = EventHolder()
self.damus_state = DamusState.empty self.damus_state = DamusState.empty
self.dms = DirectMessagesModel(our_pubkey: "") self.dms = DirectMessagesModel(our_pubkey: "")
} }
init(damus_state: DamusState) { init(damus_state: DamusState) {
self.events = EventHolder()
self.notifications = EventHolder()
self.damus_state = damus_state self.damus_state = damus_state
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
self.setup_debouncer() self.setup_debouncer()
@@ -129,6 +125,8 @@ class HomeModel: ObservableObject {
handle_channel_meta(ev) handle_channel_meta(ev)
case .zap: case .zap:
handle_zap_event(ev) handle_zap_event(ev)
case .zap_request:
break
} }
} }
@@ -143,7 +141,7 @@ class HomeModel: ObservableObject {
return return
} }
if !notifications.insert(ev) { if !notifications.insert_zap(zap) {
return return
} }
@@ -255,12 +253,11 @@ class HomeModel: ObservableObject {
return return
} }
// CHECK SIGS ON THESE
switch damus_state.likes.add_event(ev, target: e.ref_id) { switch damus_state.likes.add_event(ev, target: e.ref_id) {
case .already_counted: case .already_counted:
break break
case .success(let n): case .success(let n):
handle_notification(ev: ev)
let liked = Counted(event: ev, id: e.ref_id, total: n) let liked = Counted(event: ev, id: e.ref_id, total: n)
notify(.liked, liked) notify(.liked, liked)
notify(.update_stats, e.ref_id) notify(.update_stats, e.ref_id)
@@ -320,9 +317,9 @@ class HomeModel: ObservableObject {
if sub_id == dms_subid { if sub_id == dms_subid {
var dms = dms.dms.flatMap { $0.1.events } var dms = dms.dms.flatMap { $0.1.events }
dms.append(contentsOf: incoming_dms) dms.append(contentsOf: incoming_dms)
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: dms, damus_state: damus_state) load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, load: .from_events(dms), damus_state: damus_state)
} else if sub_id == notifications_subid { } else if sub_id == notifications_subid {
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: notifications.all_events, damus_state: damus_state) load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, load: .from_keys(notifications.uniq_pubkeys()), damus_state: damus_state)
} }
self.loading = false self.loading = false
@@ -375,7 +372,6 @@ class HomeModel: ObservableObject {
// TODO: separate likes? // TODO: separate likes?
var home_filter = NostrFilter.filter_kinds([ var home_filter = NostrFilter.filter_kinds([
NostrKind.text.rawValue, NostrKind.text.rawValue,
NostrKind.chat.rawValue,
NostrKind.like.rawValue, NostrKind.like.rawValue,
NostrKind.boost.rawValue, NostrKind.boost.rawValue,
]) ])
@@ -385,7 +381,6 @@ class HomeModel: ObservableObject {
var notifications_filter = NostrFilter.filter_kinds([ var notifications_filter = NostrFilter.filter_kinds([
NostrKind.text.rawValue, NostrKind.text.rawValue,
NostrKind.chat.rawValue,
NostrKind.like.rawValue, NostrKind.like.rawValue,
NostrKind.boost.rawValue, NostrKind.boost.rawValue,
NostrKind.zap.rawValue, NostrKind.zap.rawValue,
@@ -461,7 +456,16 @@ class HomeModel: ObservableObject {
return return
} }
if !notifications.insert(ev) { guard should_show_event(contacts: damus_state.contacts, ev: ev) else {
return
}
damus_state.events.insert(ev)
if let inner_ev = ev.inner_event {
damus_state.events.insert(inner_ev)
}
if !notifications.insert_event(ev) {
return return
} }
@@ -485,6 +489,8 @@ class HomeModel: ObservableObject {
return return
} }
damus_state.events.insert(ev)
if sub_id == home_subid { if sub_id == home_subid {
insert_home_event(ev) insert_home_event(ev)
} else if sub_id == notifications_subid { } else if sub_id == notifications_subid {

View File

@@ -263,17 +263,19 @@ func format_msats_abbrev(_ msats: Int64) -> String {
return formatter.string(from: sats) ?? sats.stringValue return formatter.string(from: sats) ?? sats.stringValue
} }
func format_msats(_ msat: Int64) -> String { func format_msats(_ msat: Int64, locale: Locale = Locale.current) -> String {
let numberFormatter = NumberFormatter() let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal numberFormatter.numberStyle = .decimal
numberFormatter.minimumFractionDigits = 0 numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 3 numberFormatter.maximumFractionDigits = 3
numberFormatter.roundingMode = .down numberFormatter.roundingMode = .down
numberFormatter.locale = locale
let sats = NSNumber(value: (Double(msat) / 1000.0)) let sats = NSNumber(value: (Double(msat) / 1000.0))
let formattedSats = numberFormatter.string(from: sats) ?? sats.stringValue let formattedSats = numberFormatter.string(from: sats) ?? sats.stringValue
return String(format: Bundle.main.localizedString(forKey: "sats_count", value: nil, table: nil), sats.decimalValue as NSDecimalNumber, formattedSats) let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "sats_count", value: nil, table: nil), locale: locale, sats.decimalValue as NSDecimalNumber, formattedSats)
} }
func convert_invoice_block(_ b: invoice_block) -> Block? { func convert_invoice_block(_ b: invoice_block) -> Block? {

View File

@@ -0,0 +1,32 @@
//
// ReactionGroup.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import Foundation
class EventGroup {
var events: [NostrEvent]
var last_event_at: Int64 {
guard let first = self.events.first else {
return 0
}
return first.created_at
}
init() {
self.events = []
}
init(events: [NostrEvent]) {
self.events = events
}
func insert(_ ev: NostrEvent) -> Bool {
return insert_uniq_sorted_event_created(events: &events, new_ev: ev)
}
}

View File

@@ -0,0 +1,53 @@
//
// ZapGroup.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import Foundation
class ZapGroup {
var zaps: [Zap]
var msat_total: Int64
var zappers: Set<String>
var last_event_at: Int64 {
guard let first = zaps.first else {
return 0
}
return first.event.created_at
}
func zap_requests() -> [NostrEvent] {
zaps.map { z in z.request.ev }
}
init(zaps: [Zap]) {
self.zaps = zaps
self.msat_total = 0
self.zappers = Set()
}
init() {
self.zaps = []
self.msat_total = 0
self.zappers = Set()
}
func insert(_ zap: Zap) -> Bool {
if !insert_uniq_sorted_zap_by_created(zaps: &zaps, new_zap: zap) {
return false
}
msat_total += zap.invoice.amount
if !zappers.contains(zap.request.ev.pubkey) {
zappers.insert(zap.request.ev.pubkey)
}
return true
}
}

View File

@@ -0,0 +1,298 @@
//
// NotificationsModel.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import Foundation
enum NotificationItem {
case repost(String, EventGroup)
case reaction(String, EventGroup)
case profile_zap(ZapGroup)
case event_zap(String, ZapGroup)
case reply(NostrEvent)
var id: String {
switch self {
case .repost(let evid, _):
return "repost_" + evid
case .reaction(let evid, _):
return "reaction_" + evid
case .profile_zap:
return "profile_zap"
case .event_zap(let evid, _):
return "event_zap_" + evid
case .reply(let ev):
return "reply_" + ev.id
}
}
var last_event_at: Int64 {
switch self {
case .reaction(_, let evgrp):
return evgrp.last_event_at
case .repost(_, let evgrp):
return evgrp.last_event_at
case .profile_zap(let zapgrp):
return zapgrp.last_event_at
case .event_zap(_, let zapgrp):
return zapgrp.last_event_at
case .reply(let reply):
return reply.created_at
}
}
}
class NotificationsModel: ObservableObject, ScrollQueue {
var incoming_zaps: [Zap]
var incoming_events: [NostrEvent]
var should_queue: Bool
// mappings from events to
var zaps: [String: ZapGroup]
var profile_zaps: ZapGroup
var reactions: [String: EventGroup]
var reposts: [String: EventGroup]
var replies: [NostrEvent]
var has_reply: Set<String>
@Published var notifications: [NotificationItem]
init() {
self.zaps = [:]
self.reactions = [:]
self.reposts = [:]
self.replies = []
self.has_reply = Set()
self.should_queue = true
self.incoming_zaps = []
self.incoming_events = []
self.profile_zaps = ZapGroup()
self.notifications = []
}
func set_should_queue(_ val: Bool) {
self.should_queue = val
}
func uniq_pubkeys() -> [String] {
var pks = Set<String>()
for ev in incoming_events {
pks.insert(ev.pubkey)
}
for grp in reposts {
for ev in grp.value.events {
pks.insert(ev.pubkey)
}
}
for ev in replies {
pks.insert(ev.pubkey)
}
for zap in incoming_zaps {
pks.insert(zap.request.ev.pubkey)
}
return Array(pks)
}
func build_notifications() -> [NotificationItem] {
var notifs: [NotificationItem] = []
for el in zaps {
let evid = el.key
let zapgrp = el.value
let notif: NotificationItem = .event_zap(evid, zapgrp)
notifs.append(notif)
}
if !profile_zaps.zaps.isEmpty {
notifs.append(.profile_zap(profile_zaps))
}
for el in reposts {
let evid = el.key
let evgrp = el.value
notifs.append(.repost(evid, evgrp))
}
for el in reactions {
let evid = el.key
let evgrp = el.value
notifs.append(.reaction(evid, evgrp))
}
for reply in replies {
notifs.append(.reply(reply))
}
notifs.sort { $0.last_event_at > $1.last_event_at }
return notifs
}
private func insert_repost(_ ev: NostrEvent) -> Bool {
guard let reposted_ev = ev.inner_event else {
return false
}
let id = reposted_ev.id
if let evgrp = self.reposts[id] {
return evgrp.insert(ev)
} else {
let evgrp = EventGroup()
self.reposts[id] = evgrp
return evgrp.insert(ev)
}
}
private func insert_text(_ ev: NostrEvent) -> Bool {
guard !has_reply.contains(ev.id) else {
return false
}
has_reply.insert(ev.id)
replies.append(ev)
return true
}
private func insert_reaction(_ ev: NostrEvent) -> Bool {
guard let ref_id = ev.referenced_ids.last else {
return false
}
let id = ref_id.id
if let evgrp = self.reactions[id] {
return evgrp.insert(ev)
} else {
let evgrp = EventGroup()
self.reactions[id] = evgrp
return evgrp.insert(ev)
}
}
private func insert_event_immediate(_ ev: NostrEvent) -> Bool {
if ev.known_kind == .boost {
return insert_repost(ev)
} else if ev.known_kind == .like {
return insert_reaction(ev)
} else if ev.known_kind == .text {
return insert_text(ev)
}
return false
}
private func insert_zap_immediate(_ zap: Zap) -> Bool {
switch zap.target {
case .note(let notezt):
let id = notezt.note_id
if let zapgrp = self.zaps[notezt.note_id] {
return zapgrp.insert(zap)
} else {
let zapgrp = ZapGroup()
self.zaps[id] = zapgrp
return zapgrp.insert(zap)
}
case .profile:
return profile_zaps.insert(zap)
}
}
func insert_event(_ ev: NostrEvent) -> Bool {
if should_queue {
return insert_uniq_sorted_event_created(events: &incoming_events, new_ev: ev)
}
if insert_event_immediate(ev) {
self.notifications = build_notifications()
return true
}
return false
}
func insert_zap(_ zap: Zap) -> Bool {
if should_queue {
return insert_uniq_sorted_zap_by_created(zaps: &incoming_zaps, new_zap: zap)
}
if insert_zap_immediate(zap) {
self.notifications = build_notifications()
return true
}
return false
}
func filter(_ isIncluded: (NostrEvent) -> Bool) {
var changed = false
var count = 0
count = incoming_events.count
incoming_events = incoming_events.filter(isIncluded)
changed = changed || incoming_events.count != count
count = profile_zaps.zaps.count
profile_zaps.zaps = profile_zaps.zaps.filter { zap in isIncluded(zap.request.ev) }
changed = changed || profile_zaps.zaps.count != count
for el in reactions {
count = el.value.events.count
el.value.events = el.value.events.filter(isIncluded)
changed = changed || el.value.events.count != count
}
for el in reposts {
count = el.value.events.count
el.value.events = el.value.events.filter(isIncluded)
changed = changed || el.value.events.count != count
}
for el in zaps {
count = el.value.zaps.count
el.value.zaps = el.value.zaps.filter {
isIncluded($0.request.ev)
}
changed = changed || el.value.zaps.count != count
}
count = replies.count
replies = replies.filter(isIncluded)
changed = changed || replies.count != count
if changed {
self.notifications = build_notifications()
}
}
func flush() -> Bool {
var inserted = false
for zap in incoming_zaps {
inserted = insert_zap_immediate(zap) || inserted
}
for event in incoming_events {
inserted = insert_event_immediate(event) || inserted
}
if inserted {
self.notifications = build_notifications()
}
return inserted
}
}

View File

@@ -76,7 +76,7 @@ class SearchHomeModel: ObservableObject {
// global events are not realtime // global events are not realtime
unsubscribe(to: relay_id) unsubscribe(to: relay_id)
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: events.all_events, damus_state: damus_state) load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, load: .from_events(events.all_events), damus_state: damus_state)
} }
@@ -99,7 +99,30 @@ func find_profiles_to_fetch_pk(profiles: Profiles, event_pubkeys: [String]) -> [
return Array(pubkeys) return Array(pubkeys)
} }
func find_profiles_to_fetch(profiles: Profiles, events: [NostrEvent]) -> [String] { func find_profiles_to_fetch(profiles: Profiles, load: PubkeysToLoad) -> [String] {
switch load {
case .from_events(let events):
return find_profiles_to_fetch_from_events(profiles: profiles, events: events)
case .from_keys(let pks):
return find_profiles_to_fetch_from_keys(profiles: profiles, pks: pks)
}
}
func find_profiles_to_fetch_from_keys(profiles: Profiles, pks: [String]) -> [String] {
var pubkeys = Set<String>()
for pk in pks {
if profiles.lookup(id: pk) != nil {
continue
}
pubkeys.insert(pk)
}
return Array(pubkeys)
}
func find_profiles_to_fetch_from_events(profiles: Profiles, events: [NostrEvent]) -> [String] {
var pubkeys = Set<String>() var pubkeys = Set<String>()
for ev in events { for ev in events {
@@ -113,9 +136,14 @@ func find_profiles_to_fetch(profiles: Profiles, events: [NostrEvent]) -> [String
return Array(pubkeys) return Array(pubkeys)
} }
func load_profiles(profiles_subid: String, relay_id: String, events: [NostrEvent], damus_state: DamusState) { enum PubkeysToLoad {
case from_events([NostrEvent])
case from_keys([String])
}
func load_profiles(profiles_subid: String, relay_id: String, load: PubkeysToLoad, damus_state: DamusState) {
var filter = NostrFilter.filter_profiles var filter = NostrFilter.filter_profiles
let authors = find_profiles_to_fetch(profiles: damus_state.profiles, events: events) let authors = find_profiles_to_fetch(profiles: damus_state.profiles, load: load)
filter.authors = authors filter.authors = authors
guard !authors.isEmpty else { guard !authors.isEmpty else {

View File

@@ -207,7 +207,7 @@ class ThreadModel: ObservableObject {
} }
if sub_id == self.base_subid { if sub_id == self.base_subid {
load_profiles(profiles_subid: self.profiles_subid, relay_id: relay_id, events: events, damus_state: damus_state) load_profiles(profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(events), damus_state: damus_state)
} }
} }

View File

@@ -50,14 +50,14 @@ class ZapsModel: ObservableObject {
break break
case .eose: case .eose:
let events = self.zaps.map { $0.request.ev } let events = self.zaps.map { $0.request.ev }
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: events, damus_state: state) load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, load: .from_events(events), damus_state: state)
case .event(_, let ev): case .event(_, let ev):
guard ev.kind == 9735 else { guard ev.kind == 9735 else {
return return
} }
if let zap = state.zaps.zaps[ev.id] { if let zap = state.zaps.zaps[ev.id] {
if insert_uniq_sorted_zap(zaps: &zaps, new_zap: zap) { if insert_uniq_sorted_zap_by_amount(zaps: &zaps, new_zap: zap) {
objectWillChange.send() objectWillChange.send()
} }
} else { } else {
@@ -71,7 +71,7 @@ class ZapsModel: ObservableObject {
state.zaps.add_zap(zap: zap) state.zaps.add_zap(zap: zap)
if insert_uniq_sorted_zap(zaps: &zaps, new_zap: zap) { if insert_uniq_sorted_zap_by_amount(zaps: &zaps, new_zap: zap) {
objectWillChange.send() objectWillChange.send()
} }
} }

View File

@@ -141,6 +141,9 @@ struct Profile: Codable {
} }
static func displayName(profile: Profile?, pubkey: String) -> String { static func displayName(profile: Profile?, pubkey: String) -> String {
if pubkey == "anon" {
return "Anonymous"
}
let pk = bech32_nopre_pubkey(pubkey) ?? pubkey let pk = bech32_nopre_pubkey(pubkey) ?? pubkey
return profile?.name ?? abbrev_pubkey(pk) return profile?.name ?? abbrev_pubkey(pk)
} }

View File

@@ -168,6 +168,9 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has
return decrypted(privkey: privkey) ?? "*failed to decrypt content*" return decrypted(privkey: privkey) ?? "*failed to decrypt content*"
} }
return content
/*
switch validity { switch validity {
case .ok: case .ok:
return content return content
@@ -176,6 +179,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has
case .bad_sig: case .bad_sig:
return content + "\n\n*WARNING: invalid signature, could be forged!*" return content + "\n\n*WARNING: invalid signature, could be forged!*"
} }
*/
} }
var description: String { var description: String {
@@ -573,14 +577,25 @@ func zap_target_to_tags(_ target: ZapTarget) -> [[String]] {
} }
} }
func make_zap_request_event(pubkey: String, privkey: String, content: String, relays: [RelayDescriptor], target: ZapTarget) -> NostrEvent { func make_zap_request_event(pubkey: String, privkey: String, content: String, relays: [RelayDescriptor], target: ZapTarget, is_anon: Bool) -> NostrEvent {
var tags = zap_target_to_tags(target) var tags = zap_target_to_tags(target)
var relay_tag = ["relays"] var relay_tag = ["relays"]
relay_tag.append(contentsOf: relays.map { $0.url.absoluteString }) relay_tag.append(contentsOf: relays.map { $0.url.absoluteString })
tags.append(relay_tag) tags.append(relay_tag)
let ev = NostrEvent(content: content, pubkey: pubkey, kind: 9734, tags: tags)
var priv = privkey
var pub = pubkey
if is_anon {
tags.append(["anon"])
let kp = generate_new_keypair()
pub = kp.pubkey
priv = kp.privkey!
}
let ev = NostrEvent(content: content, pubkey: pub, kind: 9734, tags: tags)
ev.id = calculate_event_id(ev: ev) ev.id = calculate_event_id(ev: ev)
ev.sig = sign_event(privkey: privkey, ev: ev) ev.sig = sign_event(privkey: priv, ev: ev)
return ev return ev
} }
@@ -835,7 +850,7 @@ func first_eref_mention(ev: NostrEvent, privkey: String?) -> Mention? {
extension [ReferencedId] { extension [ReferencedId] {
var pRefs: [ReferencedId] { var pRefs: [ReferencedId] {
get { get {
self.filter { ref in Set(self).filter { ref in
ref.key == "p" ref.key == "p"
} }
} }

View File

@@ -21,4 +21,5 @@ enum NostrKind: Int {
case chat = 42 case chat = 42
case list = 30000 case list = 30000
case zap = 9735 case zap = 9735
case zap_request = 9734
} }

View File

@@ -0,0 +1,27 @@
//
// EventCache.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import Foundation
class EventCache {
private var events: [String: NostrEvent]
func lookup(_ evid: String) -> NostrEvent? {
return events[evid]
}
func insert(_ ev: NostrEvent) {
guard events[ev.id] == nil else {
return
}
events[ev.id] = ev
}
init() {
self.events = [:]
}
}

View File

@@ -8,11 +8,15 @@
import Foundation import Foundation
/// Used for holding back events until they're ready to be displayed /// Used for holding back events until they're ready to be displayed
class EventHolder: ObservableObject { class EventHolder: ObservableObject, ScrollQueue {
private var has_event: Set<String> private var has_event: Set<String>
@Published var events: [NostrEvent] @Published var events: [NostrEvent]
@Published var incoming: [NostrEvent] @Published var incoming: [NostrEvent]
@Published var should_queue: Bool var should_queue: Bool
func set_should_queue(_ val: Bool) {
self.should_queue = val
}
var queued: Int { var queued: Int {
return incoming.count return incoming.count

View File

@@ -38,8 +38,7 @@ func insert_uniq_by_pubkey(events: inout [NostrEvent], new_ev: NostrEvent, cmp:
return true return true
} }
@discardableResult func insert_uniq_sorted_zap(zaps: inout [Zap], new_zap: Zap, cmp: (Zap, Zap) -> Bool) -> Bool {
func insert_uniq_sorted_zap(zaps: inout [Zap], new_zap: Zap) -> Bool {
var i: Int = 0 var i: Int = 0
for zap in zaps { for zap in zaps {
@@ -48,7 +47,7 @@ func insert_uniq_sorted_zap(zaps: inout [Zap], new_zap: Zap) -> Bool {
return false return false
} }
if new_zap.invoice.amount > zap.invoice.amount { if cmp(new_zap, zap) {
zaps.insert(new_zap, at: i) zaps.insert(new_zap, at: i)
return true return true
} }
@@ -59,6 +58,19 @@ func insert_uniq_sorted_zap(zaps: inout [Zap], new_zap: Zap) -> Bool {
return true return true
} }
@discardableResult
func insert_uniq_sorted_zap_by_created(zaps: inout [Zap], new_zap: Zap) -> Bool {
return insert_uniq_sorted_zap(zaps: &zaps, new_zap: new_zap) { (a, b) in
a.event.created_at > b.event.created_at
}
}
@discardableResult
func insert_uniq_sorted_zap_by_amount(zaps: inout [Zap], new_zap: Zap) -> Bool {
return insert_uniq_sorted_zap(zaps: &zaps, new_zap: new_zap) { (a, b) in
a.invoice.amount > b.invoice.amount
}
}
func insert_uniq_sorted_event_created(events: inout [NostrEvent], new_ev: NostrEvent) -> Bool { func insert_uniq_sorted_event_created(events: inout [NostrEvent], new_ev: NostrEvent) -> Bool {
return insert_uniq_sorted_event(events: &events, new_ev: new_ev) { return insert_uniq_sorted_event(events: &events, new_ev: new_ev) {

View File

@@ -9,8 +9,10 @@ import Foundation
struct LNUrlPayRequest: Decodable { struct LNUrlPayRequest: Decodable {
let allowsNostr: Bool? let allowsNostr: Bool?
let commentAllowed: Int?
let nostrPubkey: String? let nostrPubkey: String?
let metadata: String?
let minSendable: Int64? let minSendable: Int64?
let maxSendable: Int64? let maxSendable: Int64?
let status: String? let status: String?

View File

@@ -0,0 +1,17 @@
//
// LocalizationUtil.swift
// damus
//
// Created by Terry Yiu on 2/24/23.
//
import Foundation
func bundleForLocale(locale: Locale?) -> Bundle {
if locale == nil {
return Bundle.main
}
let path = Bundle.main.path(forResource: locale!.identifier, ofType: "lproj")
return path != nil ? (Bundle(path: path!) ?? Bundle.main) : Bundle.main
}

View File

@@ -104,6 +104,9 @@ extension Notification.Name {
static var update_bookmarks: Notification.Name { static var update_bookmarks: Notification.Name {
return Notification.Name("update_bookmarks") return Notification.Name("update_bookmarks")
} }
static var zapping: Notification.Name {
return Notification.Name("zapping")
}
} }
func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher { func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher {

View File

@@ -50,5 +50,6 @@ public func time_ago_since(_ date: Date, _ calendar: Calendar = Calendar.current
return formatter.string(from: DateComponents(calendar: calendar, second: second))! return formatter.string(from: DateComponents(calendar: calendar, second: second))!
} }
return NSLocalizedString("now", comment: "String indicating that a given timestamp just occurred") let bundle = bundleForLocale(locale: calendar.locale ?? Locale.current)
return NSLocalizedString("now", bundle: bundle, comment: "String indicating that a given timestamp just occurred")
} }

View File

@@ -285,7 +285,7 @@ func fetch_static_payreq(_ lnurl: String) async -> LNUrlPayRequest? {
return endpoint return endpoint
} }
func fetch_zap_invoice(_ payreq: LNUrlPayRequest, zapreq: NostrEvent, sats: Int) async -> String? { func fetch_zap_invoice(_ payreq: LNUrlPayRequest, zapreq: NostrEvent, sats: Int, zap_type: ZapType, comment: String?) async -> String? {
guard var base_url = payreq.callback.flatMap({ URLComponents(string: $0) }) else { guard var base_url = payreq.callback.flatMap({ URLComponents(string: $0) }) else {
return nil return nil
} }
@@ -295,13 +295,19 @@ func fetch_zap_invoice(_ payreq: LNUrlPayRequest, zapreq: NostrEvent, sats: Int)
var query = [URLQueryItem(name: "amount", value: "\(amount)")] var query = [URLQueryItem(name: "amount", value: "\(amount)")]
if zappable { if zappable && zap_type != .non_zap {
if let json = encode_json(zapreq) { if let json = encode_json(zapreq) {
print("zapreq json: \(json)") print("zapreq json: \(json)")
query.append(URLQueryItem(name: "nostr", value: json)) query.append(URLQueryItem(name: "nostr", value: json))
} }
} }
// add a lud12 comment as well if we have it
if let comment, let limit = payreq.commentAllowed, limit != 0 {
let limited_comment = String(comment.prefix(limit))
query.append(URLQueryItem(name: "comment", value: limited_comment))
}
base_url.queryItems = query base_url.queryItems = query
guard let url = base_url.url else { guard let url = base_url.url else {

View File

@@ -36,7 +36,7 @@ class Zaps {
if our_zaps[note_target.note_id] == nil { if our_zaps[note_target.note_id] == nil {
our_zaps[note_target.note_id] = [zap] our_zaps[note_target.note_id] = [zap]
} else { } else {
insert_uniq_sorted_zap(zaps: &(our_zaps[note_target.note_id]!), new_zap: zap) insert_uniq_sorted_zap_by_amount(zaps: &(our_zaps[note_target.note_id]!), new_zap: zap)
} }
case .profile(_): case .profile(_):
break break

View File

@@ -26,14 +26,16 @@ struct EventDetailBar: View {
HStack { HStack {
if bar.boosts > 0 { if bar.boosts > 0 {
NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) { NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) {
Text("\(Text(verbatim: "\(bar.boosts)").font(.body.bold())) \(Text(String(format: Bundle.main.localizedString(forKey: "reposts_count", value: nil, table: nil), bar.boosts)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.") let noun = Text(verbatim: "\(repostsCountString(bar.boosts))").foregroundColor(.gray)
Text("\(Text("\(bar.boosts)").font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
} }
if bar.likes > 0 { if bar.likes > 0 {
NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) { NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) {
Text("\(Text(verbatim: "\(bar.likes)").font(.body.bold())) \(Text(String(format: Bundle.main.localizedString(forKey: "reactions_count", value: nil, table: nil), bar.likes)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.") let noun = Text(verbatim: "\(reactionsCountString(bar.likes))").foregroundColor(.gray)
Text("\(Text("\(bar.likes)").font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.")
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
} }
@@ -41,7 +43,8 @@ struct EventDetailBar: View {
if bar.zaps > 0 { if bar.zaps > 0 {
let dst = ZapsView(state: state, target: .note(id: target, author: target_pk)) let dst = ZapsView(state: state, target: .note(id: target, author: target_pk))
NavigationLink(destination: dst) { NavigationLink(destination: dst) {
Text("\(Text(verbatim: "\(bar.zaps)").font(.body.bold())) \(Text(String(format: Bundle.main.localizedString(forKey: "zaps_count", value: nil, table: nil), bar.zaps)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.") let noun = Text(verbatim: "\(zapsCountString(bar.zaps))").foregroundColor(.gray)
Text("\(Text("\(bar.zaps)").font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.")
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
} }
@@ -49,6 +52,21 @@ struct EventDetailBar: View {
} }
} }
func repostsCountString(_ count: Int, locale: Locale = Locale.current) -> String {
let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "reposts_count", value: nil, table: nil), locale: locale, count)
}
func reactionsCountString(_ count: Int, locale: Locale = Locale.current) -> String {
let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "reactions_count", value: nil, table: nil), locale: locale, count)
}
func zapsCountString(_ count: Int, locale: Locale = Locale.current) -> String {
let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "zaps_count", value: nil, table: nil), locale: locale, count)
}
struct EventDetailBar_Previews: PreviewProvider { struct EventDetailBar_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
EventDetailBar(state: test_damus_state(), target: "", target_pk: "") EventDetailBar(state: test_damus_state(), target: "", target_pk: "")

View File

@@ -129,26 +129,14 @@ struct ConfigView: View {
} }
} }
Section(NSLocalizedString("Default Zap Amount in sats", comment: "Section title for zap configuration")) { Section(NSLocalizedString("Default Zap Amount in sats", comment: "Section title for zap configuration")) {
TextField(String("1000"), text: $default_zap_amount) TextField(String("1000"), text: $default_zap_amount)
.keyboardType(.numberPad) .keyboardType(.numberPad)
.onReceive(Just(default_zap_amount)) { newValue in .onReceive(Just(default_zap_amount)) { newValue in
let filtered = newValue.filter { Set("0123456789").contains($0) }
if filtered != newValue { if let parsed = handle_string_amount(new_value: newValue) {
default_zap_amount = filtered self.default_zap_amount = String(parsed)
} }
if filtered == "" {
set_default_zap_amount(pubkey: state.pubkey, amount: 1000)
return
}
guard let amt = Int(filtered) else {
return
}
set_default_zap_amount(pubkey: state.pubkey, amount: amt)
} }
} }
@@ -220,10 +208,10 @@ struct ConfigView: View {
} }
} }
let bundleShortVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String if let bundleShortVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"], let bundleVersion = Bundle.main.infoDictionary?["CFBundleVersion"] {
let bundleVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as! String Section(NSLocalizedString("Version", comment: "Section title for displaying the version number of the Damus app.")) {
Section(NSLocalizedString("Version", comment: "Section title for displaying the version number of the Damus app.")) { Text(verbatim: "\(bundleShortVersion) (\(bundleVersion))")
Text(verbatim: "\(bundleShortVersion) (\(bundleVersion))") }
} }
} }
} }
@@ -346,3 +334,18 @@ struct ConfigView_Previews: PreviewProvider {
} }
} }
} }
func handle_string_amount(new_value: String) -> Int? {
let filtered = new_value.filter { Set("0123456789").contains($0) }
if filtered == "" {
return nil
}
guard let amt = Int(filtered) else {
return nil
}
return amt
}

View File

@@ -37,9 +37,7 @@ struct DMChatView: View {
var Header: some View { var Header: some View {
let profile = damus_state.profiles.lookup(id: pubkey) let profile = damus_state.profiles.lookup(id: pubkey)
let pmodel = ProfileModel(pubkey: pubkey, damus: damus_state) let profile_page = ProfileView(damus_state: damus_state, pubkey: pubkey)
let fmodel = FollowersModel(damus_state: damus_state, target: pubkey)
let profile_page = ProfileView(damus_state: damus_state, profile: pmodel, followers: fmodel)
return NavigationLink(destination: profile_page) { return NavigationLink(destination: profile_page) {
HStack { HStack {
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles) ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles)

View File

@@ -41,6 +41,9 @@ struct DirectMessagesView: View {
ForEach(dms, id: \.0) { tup in ForEach(dms, id: \.0) { tup in
MaybeEvent(tup) MaybeEvent(tup)
.padding(.top, 10) .padding(.top, 10)
Divider()
.padding([.top], 10)
} }
} }
} }

View File

@@ -23,7 +23,7 @@ func scroll_after_load(thread: ThreadModel, proxy: ScrollViewProxy) {
struct EventDetailView_Previews: PreviewProvider { struct EventDetailView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let state = test_damus_state() let _ = test_damus_state()
EventDetailView() EventDetailView()
} }
} }

View File

@@ -61,10 +61,8 @@ struct EventView: View {
if event.known_kind == .boost { if event.known_kind == .boost {
if let inner_ev = event.inner_event { if let inner_ev = event.inner_event {
VStack(alignment: .leading) { VStack(alignment: .leading) {
let prof_model = ProfileModel(pubkey: event.pubkey, damus: damus)
let follow_model = FollowersModel(damus_state: damus, target: event.pubkey)
let prof = damus.profiles.lookup(id: event.pubkey) let prof = damus.profiles.lookup(id: event.pubkey)
let booster_profile = ProfileView(damus_state: damus, profile: prof_model, followers: follow_model) let booster_profile = ProfileView(damus_state: damus, pubkey: event.pubkey)
NavigationLink(destination: booster_profile) { NavigationLink(destination: booster_profile) {
Reposted(damus: damus, pubkey: event.pubkey, profile: prof) Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
@@ -86,9 +84,6 @@ struct EventView: View {
TextEvent(damus: damus, event: event, pubkey: pubkey, has_action_bar: has_action_bar, booster_pubkey: nil) TextEvent(damus: damus, event: event, pubkey: pubkey, has_action_bar: has_action_bar, booster_pubkey: nil)
.padding([.top], 6) .padding([.top], 6)
} }
Divider()
.padding([.top], 4)
} }
} }
} }

View File

@@ -71,8 +71,10 @@ struct BuilderEventView: View {
} }
} }
.frame(minWidth: 0, maxWidth: .infinity) .frame(minWidth: 0, maxWidth: .infinity)
.cornerRadius(8) .overlay(
.border(Color.gray.opacity(0.2), width: 1) RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.2), lineWidth: 1.0)
)
.onAppear { .onAppear {
self.load() self.load()
} }

View File

@@ -11,6 +11,14 @@ struct EventBody: View {
let damus_state: DamusState let damus_state: DamusState
let event: NostrEvent let event: NostrEvent
let size: EventViewKind let size: EventViewKind
let should_show_img: Bool
init(damus_state: DamusState, event: NostrEvent, size: EventViewKind, should_show_img: Bool? = nil) {
self.damus_state = damus_state
self.event = event
self.size = size
self.should_show_img = should_show_img ?? should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
}
var content: String { var content: String {
event.get_content(damus_state.keypair.privkey) event.get_content(damus_state.keypair.privkey)
@@ -21,8 +29,6 @@ struct EventBody: View {
ReplyDescription(event: event, profiles: damus_state.profiles) ReplyDescription(event: event, profiles: damus_state.profiles)
} }
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey, booster_pubkey: nil)
NoteContentView(damus_state: damus_state, event: event, show_images: should_show_img, size: size, artifacts: .just_content(content)) NoteContentView(damus_state: damus_state, event: event, show_images: should_show_img, size: size, artifacts: .just_content(content))
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }

View File

@@ -47,9 +47,9 @@ struct EventMenuContext: View {
notify(.update_bookmarks, event) notify(.update_bookmarks, event)
} label: { } label: {
let imageName = isBookmarked ? "bookmark.fill" : "bookmark" let imageName = isBookmarked ? "bookmark.fill" : "bookmark"
let unBookmarkString = NSLocalizedString("Un-Bookmark", comment: "Context menu option for un-bookmarking a note") let removeBookmarkString = NSLocalizedString("Remove Bookmark", comment: "Context menu option for removing a note bookmark.")
let bookmarkString = NSLocalizedString("Bookmark", comment: "Context menu optoin for bookmarking a note") let addBookmarkString = NSLocalizedString("Add Bookmark", comment: "Context menu option for adding a note bookmark.")
Label(isBookmarked ? unBookmarkString : bookmarkString, systemImage: imageName) Label(isBookmarked ? removeBookmarkString : addBookmarkString, systemImage: imageName)
} }
.onAppear { .onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {

View File

@@ -31,10 +31,7 @@ struct EventProfile: View {
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
VStack { VStack {
let pmodel = ProfileModel(pubkey: pubkey, damus: damus_state) NavigationLink(destination: ProfileView(damus_state: damus_state, pubkey: pubkey)) {
let pv = ProfileView(damus_state: damus_state, profile: pmodel, followers: FollowersModel(damus_state: damus_state, target: pubkey))
NavigationLink(destination: pv) {
ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles) ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles)
} }
} }

View File

@@ -26,13 +26,15 @@ struct ReplyDescription_Previews: PreviewProvider {
} }
} }
func reply_desc(profiles: Profiles, event: NostrEvent) -> String { func reply_desc(profiles: Profiles, event: NostrEvent, locale: Locale = Locale.current) -> String {
let desc = make_reply_description(event.tags) let desc = make_reply_description(event.tags)
let pubkeys = desc.pubkeys let pubkeys = desc.pubkeys
let n = desc.others let n = desc.others
let bundle = bundleForLocale(locale: locale)
if desc.pubkeys.count == 0 { if desc.pubkeys.count == 0 {
return NSLocalizedString("Replying to self", comment: "Label to indicate that the user is replying to themself.") return NSLocalizedString("Replying to self", bundle: bundle, comment: "Label to indicate that the user is replying to themself.")
} }
let names: [String] = pubkeys.map { let names: [String] = pubkeys.map {
@@ -40,20 +42,16 @@ func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
return Profile.displayName(profile: prof, pubkey: $0) return Profile.displayName(profile: prof, pubkey: $0)
} }
let othersCount = n - pubkeys.count
if names.count > 1 { if names.count > 1 {
let othersCount = n - pubkeys.count
if othersCount == 0 { if othersCount == 0 {
return String(format: "Replying to %@ & %@", names[0], names[1]) return String(format: NSLocalizedString("Replying to %@ & %@", bundle: bundle, comment: "Label to indicate that the user is replying to 2 users."), locale: locale, names[0], names[1])
} else { } else {
return String(format: "Replying to %@, %@ & %d others", names[0], names[1], othersCount) return String(format: bundle.localizedString(forKey: "replying_to_two_and_others", value: nil, table: nil), locale: locale, othersCount, names[0], names[1])
} }
} }
if othersCount == 0 { return String(format: NSLocalizedString("Replying to %@", bundle: bundle, comment: "Label to indicate that the user is replying to 1 user."), locale: locale, names[0])
return String(format: "Replying to %@", names[0])
} else {
return String(format: "Replying to %@ & %d others", names[0], othersCount)
}
} }

View File

@@ -18,20 +18,17 @@ struct TextEvent: View {
HStack(alignment: .top) { HStack(alignment: .top) {
let profile = damus.profiles.lookup(id: pubkey) let profile = damus.profiles.lookup(id: pubkey)
let is_anon = event_is_anonymous(ev: event)
VStack { VStack {
let pmodel = ProfileModel(pubkey: pubkey, damus: damus) MaybeAnonPfpView(state: damus, is_anon: is_anon, pubkey: pubkey)
let pv = ProfileView(damus_state: damus, profile: pmodel, followers: FollowersModel(damus_state: damus, target: pubkey))
NavigationLink(destination: pv) {
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus.profiles)
}
Spacer() Spacer()
} }
VStack(alignment: .leading) { VStack(alignment: .leading) {
HStack(alignment: .center) { HStack(alignment: .center) {
EventProfileName(pubkey: pubkey, profile: profile, damus: damus, show_friend_confirmed: true, size: .normal) let pk = is_anon ? "anon" : pubkey
EventProfileName(pubkey: pk, profile: profile, damus: damus, show_friend_confirmed: true, size: .normal)
Text(verbatim: "\(format_relative_time(event.created_at))") Text(verbatim: "\(format_relative_time(event.created_at))")
.foregroundColor(.gray) .foregroundColor(.gray)
@@ -68,3 +65,18 @@ struct TextEvent_Previews: PreviewProvider {
TextEvent(damus: test_damus_state(), event: test_event, pubkey: "pk", has_action_bar: true, booster_pubkey: nil) TextEvent(damus: test_damus_state(), event: test_event, pubkey: "pk", has_action_bar: true, booster_pubkey: nil)
} }
} }
func event_has_tag(ev: NostrEvent, tag: String) -> Bool {
for t in ev.tags {
if t.count >= 1 && t[0] == tag {
return true
}
}
return false
}
func event_is_anonymous(ev: NostrEvent) -> Bool {
return ev.known_kind == .zap_request && event_has_tag(ev: ev, tag: "anon")
}

View File

@@ -19,7 +19,7 @@ struct FollowButtonView: View {
Button { Button {
follow_state = perform_follow_btn_action(follow_state, target: target) follow_state = perform_follow_btn_action(follow_state, target: target)
} label: { } label: {
Text(follow_btn_txt(follow_state, follows_you: follows_you)) Text(verbatim: "\(follow_btn_txt(follow_state, follows_you: follows_you))")
.frame(width: 105, height: 30) .frame(width: 105, height: 30)
//.padding(.vertical, 10) //.padding(.vertical, 10)
.font(.caption.weight(.bold)) .font(.caption.weight(.bold))

View File

@@ -29,7 +29,6 @@ struct FollowersView: View {
@EnvironmentObject var followers: FollowersModel @EnvironmentObject var followers: FollowersModel
var body: some View { var body: some View {
let profile = damus_state.profiles.lookup(id: whos)
ScrollView { ScrollView {
LazyVStack(alignment: .leading) { LazyVStack(alignment: .leading) {
ForEach(followers.contacts ?? [], id: \.self) { pk in ForEach(followers.contacts ?? [], id: \.self) { pk in
@@ -38,7 +37,7 @@ struct FollowersView: View {
} }
.padding() .padding()
} }
.navigationBarTitle(NSLocalizedString("\(Profile.displayName(profile: profile, pubkey: whos))'s Followers", comment: "Navigation bar title for view that shows who is following a user.")) .navigationBarTitle(NSLocalizedString("Followers", comment: "Navigation bar title for view that shows who is following a user."))
.onAppear { .onAppear {
followers.subscribe() followers.subscribe()
} }
@@ -56,8 +55,6 @@ struct FollowingView: View {
let whos: String let whos: String
var body: some View { var body: some View {
let profile = damus_state.profiles.lookup(id: whos)
let who = Profile.displayName(profile: profile, pubkey: whos)
ScrollView { ScrollView {
LazyVStack(alignment: .leading) { LazyVStack(alignment: .leading) {
ForEach(following.contacts, id: \.self) { pk in ForEach(following.contacts, id: \.self) { pk in
@@ -72,7 +69,7 @@ struct FollowingView: View {
.onDisappear { .onDisappear {
following.unsubscribe() following.unsubscribe()
} }
.navigationBarTitle(NSLocalizedString("\(who) following", comment: "Navigation bar title for view that shows who a user is following.")) .navigationBarTitle(NSLocalizedString("Following", comment: "Navigation bar title for view that shows who a user is following."))
} }
} }

View File

@@ -0,0 +1,214 @@
//
// RepostGroupView.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import SwiftUI
enum EventGroupType {
case repost(EventGroup)
case reaction(EventGroup)
case zap(ZapGroup)
case profile_zap(ZapGroup)
var events: [NostrEvent] {
switch self {
case .repost(let grp):
return grp.events
case .reaction(let grp):
return grp.events
case .zap(let zapgrp):
return zapgrp.zap_requests()
case .profile_zap(let zapgrp):
return zapgrp.zap_requests()
}
}
}
enum ReactingTo {
case your_post
case tagged_in
case your_profile
}
func determine_reacting_to(our_pubkey: String, ev: NostrEvent?) -> ReactingTo {
guard let ev else {
return .your_profile
}
if ev.pubkey == our_pubkey {
return .your_post
}
return .tagged_in
}
func event_author_name(profiles: Profiles, _ ev: NostrEvent) -> String {
let alice_pk = ev.pubkey
let alice_prof = profiles.lookup(id: alice_pk)
return Profile.displayName(profile: alice_prof, pubkey: alice_pk)
}
/**
Returns a notification string describing user actions in response to an event group type.
The localization keys read by this function are the following (although some keys may not actually be used in practice):
"??" - returned when there are no events associated with the specified event group type.
"reacted_tagged_in_1" - returned when 1 reaction occurred to a post that the current user was tagged in
"reacted_tagged_in_2" - returned when 2 reactions occurred to a post that the current user was tagged in
"reacted_tagged_in_3" - returned when 3 or more reactions occurred to a post that the current user was tagged in
"reacted_your_post_1" - returned when 1 reaction occurred to the current user's post
"reacted_your_post_2" - returned when 2 reactions occurred to the current user's post
"reacted_your_post_3" - returned when 3 or more reactions occurred to the current user's post
"reacted_your_profile_1" - returned when 1 reaction occurred to the current user's profile
"reacted_your_profile_2" - returned when 2 reactions occurred to the current user's profile
"reacted_your_profile_3" - returned when 3 or more reactions occurred to the current user's profile
"reposted_tagged_in_1" - returned when 1 repost occurred to a post that the current user was tagged in
"reposted_tagged_in_2" - returned when 2 reposts occurred to a post that the current user was tagged in
"reposted_tagged_in_3" - returned when 3 or more reposts occurred to a post that the current user was tagged in
"reposted_your_post_1" - returned when 1 repost occurred to the current user's post
"reposted_your_post_2" - returned when 2 reposts occurred to the current user's post
"reposted_your_post_3" - returned when 3 or more reposts occurred to the current user's post
"reposted_your_profile_1" - returned when 1 repost occurred to the current user's profile
"reposted_your_profile_2" - returned when 2 reposts occurred to the current user's profile
"reposted_your_profile_3" - returned when 3 or more reposts occurred to the current user's profile
"zapped_tagged_in_1" - returned when 1 zap occurred to a post that the current user was tagged in
"zapped_tagged_in_2" - returned when 2 zaps occurred to a post that the current user was tagged in
"zapped_tagged_in_3" - returned when 3 or more zaps occurred to a post that the current user was tagged in
"zapped_your_post_1" - returned when 1 zap occurred to the current user's post
"zapped_your_post_2" - returned when 2 zaps occurred to the current user's post
"zapped_your_post_3" - returned when 3 or more zaps occurred to the current user's post
"zapped_your_profile_1" - returned when 1 zap occurred to the current user's profile
"zapped_your_profile_2" - returned when 2 zaps occurred to the current user's profile
"zapped_your_profile_3" - returned when 3 or more zaps occurred to the current user's profile
*/
func reacting_to_text(profiles: Profiles, our_pubkey: String, group: EventGroupType, ev: NostrEvent?, locale: Locale? = nil) -> String {
let verb = reacting_to_verb(group: group)
let reacting_to = determine_reacting_to(our_pubkey: our_pubkey, ev: ev)
let localization_key = "\(verb)_\(reacting_to)_\(min(group.events.count, 3))"
let bundle = bundleForLocale(locale: locale)
switch group.events.count {
case 0:
return NSLocalizedString("??", comment: "")
case 1:
let ev = group.events.first!
let profile = profiles.lookup(id: ev.pubkey)
let display_name = Profile.displayName(profile: profile, pubkey: ev.pubkey)
return String(format: bundle.localizedString(forKey: localization_key, value: bundleForLocale(locale: Locale(identifier: "en-US")).localizedString(forKey: localization_key, value: nil, table: nil), table: nil), locale: locale, display_name)
case 2:
let alice_name = event_author_name(profiles: profiles, group.events[0])
let bob_name = event_author_name(profiles: profiles, group.events[1])
return String(format: bundle.localizedString(forKey: localization_key, value: bundleForLocale(locale: Locale(identifier: "en-US")).localizedString(forKey: localization_key, value: nil, table: nil), table: nil), locale: locale, alice_name, bob_name)
default:
let alice_name = event_author_name(profiles: profiles, group.events.first!)
let count = group.events.count - 1
return String(format: bundle.localizedString(forKey: localization_key, value: bundleForLocale(locale: Locale(identifier: "en-US")).localizedString(forKey: localization_key, value: nil, table: nil), table: nil), locale: locale, count, alice_name)
}
}
func reacting_to_verb(group: EventGroupType) -> String {
switch group {
case .reaction:
return "reacted"
case .repost:
return "reposted"
case .zap: fallthrough
case .profile_zap:
return "zapped"
}
}
struct EventGroupView: View {
let state: DamusState
let event: NostrEvent?
let group: EventGroupType
var GroupDescription: some View {
Text(verbatim: "\(reacting_to_text(profiles: state.profiles, our_pubkey: state.pubkey, group: group, ev: event))")
}
func ZapIcon(_ zapgrp: ZapGroup) -> some View {
let fmt = format_msats_abbrev(zapgrp.msat_total)
return VStack(alignment: .center) {
Image(systemName: "bolt.fill")
.foregroundColor(.orange)
Text("\(fmt)")
.foregroundColor(Color.orange)
}
}
var GroupIcon: some View {
Group {
switch group {
case .repost:
Image(systemName: "arrow.2.squarepath")
.foregroundColor(Color("DamusGreen"))
case .reaction:
Image("shaka-full")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(.accentColor)
case .profile_zap(let zapgrp):
ZapIcon(zapgrp)
case .zap(let zapgrp):
ZapIcon(zapgrp)
}
}
}
var body: some View {
HStack(alignment: .top) {
GroupIcon
.frame(width: PFP_SIZE + 10)
VStack(alignment: .leading) {
ProfilePicturesView(state: state, events: group.events)
GroupDescription
if let event {
NavigationLink(destination: BuildThreadV2View(damus: state, event_id: event.id)) {
Text(event.content)
.padding([.top], 1)
.foregroundColor(.gray)
}
.buttonStyle(.plain)
}
}
}
.padding([.top], 6)
}
}
let test_encoded_post = "{\"id\": \"8ba545ab96959fe0ce7db31bc10f3ac3aa5353bc4428dbf1e56a7be7062516db\",\"pubkey\": \"7e27509ccf1e297e1df164912a43406218f8bd80129424c3ef798ca3ef5c8444\",\"created_at\": 1677013417,\"kind\": 1,\"tags\": [],\"content\": \"hello\",\"sig\": \"93684f15eddf11f42afbdd81828ee9fc35350344d8650c78909099d776e9ad8d959cd5c4bff7045be3b0b255144add43d0feef97940794a1bc9c309791bebe4a\"}"
let test_repost_1 = NostrEvent(id: "", content: test_encoded_post, pubkey: "pk1", kind: 6, tags: [], createdAt: 1)
let test_repost_2 = NostrEvent(id: "", content: test_encoded_post, pubkey: "pk2", kind: 6, tags: [], createdAt: 1)
let test_reposts = [test_repost_1, test_repost_2]
let test_event_group = EventGroup(events: test_reposts)
struct EventGroupView_Previews: PreviewProvider {
static var previews: some View {
VStack {
EventGroupView(state: test_damus_state(), event: test_event, group: .repost(test_event_group))
.frame(height: 200)
.padding()
EventGroupView(state: test_damus_state(), event: test_event, group: .reaction(test_event_group))
.frame(height: 200)
.padding()
}
}
}

View File

@@ -0,0 +1,86 @@
//
// NotificationItemView.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import SwiftUI
enum ShowItem {
case show(NostrEvent?)
case dontshow(NostrEvent?)
}
func notification_item_event(events: EventCache, notif: NotificationItem) -> ShowItem {
switch notif {
case .repost(let evid, _):
return .dontshow(events.lookup(evid))
case .reply(let ev):
return .show(ev)
case .reaction(let evid, _):
return .dontshow(events.lookup(evid))
case .event_zap(let evid, _):
return .dontshow(events.lookup(evid))
case .profile_zap:
return .show(nil)
}
}
struct NotificationItemView: View {
let state: DamusState
let item: NotificationItem
var show_item: ShowItem {
notification_item_event(events: state.events, notif: item)
}
func Item(_ ev: NostrEvent?) -> some View {
Group {
switch item {
case .repost(_, let evgrp):
EventGroupView(state: state, event: ev, group: .repost(evgrp))
case .event_zap(_, let zapgrp):
EventGroupView(state: state, event: ev, group: .zap(zapgrp))
case .profile_zap(let grp):
EventGroupView(state: state, event: nil, group: .profile_zap(grp))
case .reaction(_, let evgrp):
EventGroupView(state: state, event: ev, group: .reaction(evgrp))
case .reply(let ev):
NavigationLink(destination: BuildThreadV2View(damus: state, event_id: ev.id)) {
EventView(damus: state, event: ev, has_action_bar: true)
}
.buttonStyle(.plain)
}
Divider()
.padding([.top,.bottom], 5)
}
}
var body: some View {
Group {
switch show_item {
case .show(let ev):
Item(ev)
case .dontshow(let ev):
if let ev {
Item(ev)
}
}
}
}
}
let test_notification_item: NotificationItem = .repost("evid", test_event_group)
struct NotificationItemView_Previews: PreviewProvider {
static var previews: some View {
NotificationItemView(state: test_damus_state(), item: test_notification_item)
}
}

View File

@@ -0,0 +1,50 @@
//
// NotificationsView.swift
// damus
//
// Created by William Casarin on 2023-02-21.
//
import SwiftUI
struct NotificationsView: View {
let state: DamusState
@ObservedObject var notifications: NotificationsModel
var body: some View {
ScrollViewReader { scroller in
ScrollView {
LazyVStack(alignment: .leading) {
Color.white.opacity(0)
.id("startblock")
.frame(height: 5)
ForEach(notifications.notifications, id: \.id) { item in
NotificationItemView(state: state, item: item)
}
}
.background(GeometryReader { proxy -> Color in
DispatchQueue.main.async {
handle_scroll_queue(proxy, queue: self.notifications)
}
return Color.clear
})
.padding(.horizontal)
}
.coordinateSpace(name: "scroll")
.onReceive(handle_notify(.scroll_to_top)) { notif in
let _ = notifications.flush()
self.notifications.should_queue = false
scroll_to_event(scroller: scroller, id: "startblock", delay: 0.0, animate: true, anchor: .top)
}
}
.onAppear {
let _ = notifications.flush()
}
}
}
struct NotificationsView_Previews: PreviewProvider {
static var previews: some View {
NotificationsView(state: test_damus_state(), notifications: NotificationsModel())
}
}

View File

@@ -0,0 +1,37 @@
//
// ProfilePicturesView.swift
// damus
//
// Created by William Casarin on 2023-02-22.
//
import SwiftUI
struct ProfilePicturesView: View {
let state: DamusState
let events: [NostrEvent]
@State var nav_target: String? = nil
@State var navigating: Bool = false
var body: some View {
NavigationLink(destination: ProfileView(damus_state: state, pubkey: nav_target ?? ""), isActive: $navigating) {
EmptyView()
}
HStack {
ForEach(events.prefix(8)) { ev in
ProfilePicView(pubkey: ev.pubkey, size: 32.0, highlight: .none, profiles: state.profiles)
.onTapGesture {
nav_target = ev.pubkey
navigating = true
}
}
}
}
}
struct ProfilePicturesView_Previews: PreviewProvider {
static var previews: some View {
ProfilePicturesView(state: test_damus_state(), events: [test_event, test_event])
}
}

View File

@@ -36,37 +36,39 @@ struct ParticipantsView: View {
Spacer() Spacer()
} }
VStack { VStack {
ForEach(originalReferences.pRefs) { participant in ScrollView {
let pubkey = participant.id ForEach(originalReferences.pRefs) { participant in
HStack { let pubkey = participant.id
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles) HStack {
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles)
VStack(alignment: .leading) { VStack(alignment: .leading) {
let profile = damus_state.profiles.lookup(id: pubkey) let profile = damus_state.profiles.lookup(id: pubkey)
ProfileName(pubkey: pubkey, profile: profile, damus: damus_state, show_friend_confirmed: false, show_nip5_domain: false) ProfileName(pubkey: pubkey, profile: profile, damus: damus_state, show_friend_confirmed: false, show_nip5_domain: false)
if let about = profile?.about { if let about = profile?.about {
Text(FollowUserView.markdown.process(about)) Text(FollowUserView.markdown.process(about))
.lineLimit(3) .lineLimit(3)
.font(.footnote) .font(.footnote)
}
} }
Spacer()
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 30))
.foregroundColor(references.contains(participant) ? .purple : .gray)
} }
.onTapGesture {
Spacer()
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 30))
.foregroundColor(references.contains(participant) ? .purple : .gray)
}
.onTapGesture {
if references.contains(participant) {
references = references.filter {
$0 != participant
}
} else {
if references.contains(participant) { if references.contains(participant) {
// Don't add it twice references = references.filter {
$0 != participant
}
} else { } else {
references.append(participant) if references.contains(participant) {
// Don't add it twice
} else {
references.append(participant)
}
} }
} }
} }

View File

@@ -15,7 +15,7 @@ enum NostrPostResult {
let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Text box prompt to ask user to type their post.") let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Text box prompt to ask user to type their post.")
struct PostView: View { struct PostView: View {
@State var post: String = "" @State var post: NSMutableAttributedString = NSMutableAttributedString()
@FocusState var focus: Bool @FocusState var focus: Bool
@State var showPrivateKeyWarning: Bool = false @State var showPrivateKeyWarning: Bool = false
@@ -44,7 +44,14 @@ struct PostView: View {
if replying_to?.known_kind == .chat { if replying_to?.known_kind == .chat {
kind = .chat kind = .chat
} }
let content = self.post.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
post.enumerateAttributes(in: NSRange(location: 0, length: post.length), options: []) { attributes, range, stop in
if let link = attributes[.link] as? String {
post.replaceCharacters(in: range, with: link)
}
}
let content = self.post.string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
let new_post = NostrPost(content: content, references: references, kind: kind) let new_post = NostrPost(content: content, references: references, kind: kind)
NotificationCenter.default.post(name: .post, object: NostrPostResult.post(new_post)) NotificationCenter.default.post(name: .post, object: NostrPostResult.post(new_post))
@@ -52,14 +59,14 @@ struct PostView: View {
if let replying_to { if let replying_to {
damus_state.drafts.replies.removeValue(forKey: replying_to) damus_state.drafts.replies.removeValue(forKey: replying_to)
} else { } else {
damus_state.drafts.post = "" damus_state.drafts.post = NSMutableAttributedString(string: "")
} }
dismiss() dismiss()
} }
var is_post_empty: Bool { var is_post_empty: Bool {
return post.allSatisfy { $0.isWhitespace } return post.string.allSatisfy { $0.isWhitespace }
} }
var body: some View { var body: some View {
@@ -74,7 +81,7 @@ struct PostView: View {
if !is_post_empty { if !is_post_empty {
Button(NSLocalizedString("Post", comment: "Button to post a note.")) { Button(NSLocalizedString("Post", comment: "Button to post a note.")) {
showPrivateKeyWarning = contentContainsPrivateKey(self.post) showPrivateKeyWarning = contentContainsPrivateKey(self.post.string)
if !showPrivateKeyWarning { if !showPrivateKeyWarning {
self.send_post() self.send_post()
@@ -97,7 +104,7 @@ struct PostView: View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
TextEditor(text: $post) TextViewWrapper(attributedText: $post)
.focused($focus) .focused($focus)
.textInputAutocapitalization(.sentences) .textInputAutocapitalization(.sentences)
.onChange(of: post) { _ in .onChange(of: post) { _ in
@@ -108,7 +115,7 @@ struct PostView: View {
} }
} }
if post.isEmpty { if post.string.isEmpty {
Text(POST_PLACEHOLDER) Text(POST_PLACEHOLDER)
.padding(.top, 8) .padding(.top, 8)
.padding(.leading, 4) .padding(.leading, 4)
@@ -120,7 +127,7 @@ struct PostView: View {
} }
// This if-block observes @ for tagging // This if-block observes @ for tagging
if let searching = get_searching_string(post) { if let searching = get_searching_string(post.string) {
VStack { VStack {
Spacer() Spacer()
UserSearch(damus_state: damus_state, search: searching, post: $post) UserSearch(damus_state: damus_state, search: searching, post: $post)
@@ -130,7 +137,7 @@ struct PostView: View {
.onAppear() { .onAppear() {
if let replying_to { if let replying_to {
if damus_state.drafts.replies[replying_to] == nil { if damus_state.drafts.replies[replying_to] == nil {
damus_state.drafts.replies[replying_to] = "" damus_state.drafts.post = NSMutableAttributedString(string: "")
} }
if let p = damus_state.drafts.replies[replying_to] { if let p = damus_state.drafts.replies[replying_to] {
post = p post = p
@@ -144,10 +151,10 @@ struct PostView: View {
} }
} }
.onDisappear { .onDisappear {
if let replying_to, let reply = damus_state.drafts.replies[replying_to], reply.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { if let replying_to, let reply = damus_state.drafts.replies[replying_to], reply.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
damus_state.drafts.replies.removeValue(forKey: replying_to) damus_state.drafts.replies.removeValue(forKey: replying_to)
} else if replying_to == nil && damus_state.drafts.post.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { } else if replying_to == nil && damus_state.drafts.post.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
damus_state.drafts.post = "" damus_state.drafts.post = NSMutableAttributedString(string : "")
} }
} }
.padding() .padding()

View File

@@ -20,7 +20,8 @@ struct SearchedUser: Identifiable {
struct UserSearch: View { struct UserSearch: View {
let damus_state: DamusState let damus_state: DamusState
let search: String let search: String
@Binding var post: String
@Binding var post: NSMutableAttributedString
var users: [SearchedUser] { var users: [SearchedUser] {
guard let contacts = damus_state.contacts.event else { guard let contacts = damus_state.contacts.event else {
@@ -39,7 +40,26 @@ struct UserSearch: View {
guard let pk = bech32_pubkey(user.pubkey) else { guard let pk = bech32_pubkey(user.pubkey) else {
return return
} }
post = post.replacingOccurrences(of: "@"+search, with: "@"+pk+" ")
while post.string.last != "@" {
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
}
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
var tagString = ""
if let name = user.profile?.name {
tagString = "@\(name)\u{200B} "
}
let tagAttributedString = NSMutableAttributedString(string: tagString,
attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18.0),
NSAttributedString.Key.link: "@\(pk)"])
tagAttributedString.removeAttribute(.link, range: NSRange(location: tagAttributedString.length - 2, length: 2))
tagAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.label], range: NSRange(location: tagAttributedString.length - 2, length: 2))
let mutableString = NSMutableAttributedString()
mutableString.append(post)
mutableString.append(tagAttributedString)
post = mutableString
} }
} }
} }
@@ -49,7 +69,7 @@ struct UserSearch: View {
struct UserSearch_Previews: PreviewProvider { struct UserSearch_Previews: PreviewProvider {
static let search: String = "jb55" static let search: String = "jb55"
@State static var post: String = "some @jb55" @State static var post: NSMutableAttributedString = NSMutableAttributedString(string: "some @jb55")
static var previews: some View { static var previews: some View {
UserSearch(damus_state: test_damus_state(), search: search, post: $post) UserSearch(damus_state: test_damus_state(), search: search, post: $post)

View File

@@ -0,0 +1,46 @@
//
// MaybeAnonPfpView.swift
// damus
//
// Created by William Casarin on 2023-02-26.
//
import SwiftUI
struct MaybeAnonPfpView: View {
let state: DamusState
let is_anon: Bool
let pubkey: String
init(state: DamusState, event: NostrEvent, pubkey: String) {
self.state = state
self.is_anon = event_is_anonymous(ev: event)
self.pubkey = pubkey
}
init(state: DamusState, is_anon: Bool, pubkey: String) {
self.state = state
self.is_anon = is_anon
self.pubkey = pubkey
}
var body: some View {
Group {
if is_anon {
Image(systemName: "person.fill.questionmark")
.font(.largeTitle)
.frame(width: PFP_SIZE, height: PFP_SIZE)
} else {
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pubkey)) {
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: state.profiles)
}
}
}
}
}
struct MaybeAnonPfpView_Previews: PreviewProvider {
static var previews: some View {
MaybeAnonPfpView(state: test_damus_state(), is_anon: true, pubkey: "anon")
}
}

View File

@@ -67,7 +67,7 @@ struct ProfileName: View {
var body: some View { var body: some View {
HStack(spacing: 2) { HStack(spacing: 2) {
Text(prefix + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey))) Text(verbatim: "\(prefix)\(String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))")
.font(.body) .font(.body)
.fontWeight(prefix == "@" ? .none : .bold) .fontWeight(prefix == "@" ? .none : .bold)
if let nip05 = current_nip05 { if let nip05 = current_nip05 {
@@ -136,11 +136,11 @@ struct EventProfileName: View {
.font(.body.weight(.bold)) .font(.body.weight(.bold))
.padding([.trailing], 2) .padding([.trailing], 2)
Text("@" + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey))) Text(verbatim: "@\(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey))")
.foregroundColor(Color("DamusMediumGrey")) .foregroundColor(Color("DamusMediumGrey"))
.font(eventviewsize_to_font(size)) .font(eventviewsize_to_font(size))
} else { } else {
Text(String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey))) Text(verbatim: "\(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey))")
.font(eventviewsize_to_font(size)) .font(eventviewsize_to_font(size))
.fontWeight(.bold) .fontWeight(.bold)
} }

View File

@@ -49,6 +49,16 @@ func follow_btn_enabled_state(_ fs: FollowState) -> Bool {
} }
} }
func followersCountString(_ count: Int, locale: Locale = Locale.current) -> String {
let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "followers_count", value: nil, table: nil), locale: locale, count)
}
func relaysCountString(_ count: Int, locale: Locale = Locale.current) -> String {
let bundle = bundleForLocale(locale: locale)
return String(format: bundle.localizedString(forKey: "relays_count", value: nil, table: nil), locale: locale, count)
}
struct EditButton: View { struct EditButton: View {
let damus_state: DamusState let damus_state: DamusState
@@ -100,8 +110,6 @@ struct ProfileView: View {
static let markdown = Markdown() static let markdown = Markdown()
@State private var selected_tab: ProfileTab = .posts @State private var selected_tab: ProfileTab = .posts
@StateObject var profile: ProfileModel
@StateObject var followers: FollowersModel
@State private var showingEditProfile = false @State private var showingEditProfile = false
@State var showing_select_wallet: Bool = false @State var showing_select_wallet: Bool = false
@State var is_zoomed: Bool = false @State var is_zoomed: Bool = false
@@ -110,6 +118,21 @@ struct ProfileView: View {
@State var filter_state : FilterState = .posts @State var filter_state : FilterState = .posts
@State var yOffset: CGFloat = 0 @State var yOffset: CGFloat = 0
@StateObject var profile: ProfileModel
@StateObject var followers: FollowersModel
init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) {
self.damus_state = damus_state
self._profile = StateObject(wrappedValue: profile)
self._followers = StateObject(wrappedValue: followers)
}
init(damus_state: DamusState, pubkey: String) {
self.damus_state = damus_state
self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state))
self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey))
}
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.openURL) var openURL @Environment(\.openURL) var openURL
@@ -319,7 +342,8 @@ struct ProfileView: View {
.foregroundColor(.gray) .foregroundColor(.gray)
} else { } else {
let followerCount = followers.count! let followerCount = followers.count!
Text("\(Text(verbatim: "\(followerCount)").font(.subheadline.weight(.medium))) \(Text(String(format: Bundle.main.localizedString(forKey: "followers_count", value: nil, table: nil), followerCount)).font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.") let noun_text = Text(verbatim: "\(followersCountString(followerCount))").font(.subheadline).foregroundColor(.gray)
Text("\(Text("\(followerCount)").font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.")
} }
} }
} }
@@ -343,7 +367,8 @@ struct ProfileView: View {
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts) let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
NavigationLink(destination: FollowingView(damus_state: damus_state, following: following_model, whos: profile.pubkey)) { NavigationLink(destination: FollowingView(damus_state: damus_state, following: following_model, whos: profile.pubkey)) {
HStack { HStack {
Text("\(Text(verbatim: "\(profile.following)").font(.subheadline.weight(.medium))) \(Text("Following", comment: "Part of a larger sentence to describe how many profiles a user is following.").font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.") let noun_text = Text("Following", comment: "Text on the user profile page next to the number of accounts a user is following.").font(.subheadline).foregroundColor(.gray)
Text("\(Text("\(profile.following)").font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.")
} }
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
@@ -366,7 +391,8 @@ struct ProfileView: View {
if let relays = profile.relays { if let relays = profile.relays {
// Only open relay config view if the user is logged in with private key and they are looking at their own profile. // Only open relay config view if the user is logged in with private key and they are looking at their own profile.
let relay_text = Text("\(Text(verbatim: "\(relays.keys.count)").font(.subheadline.weight(.medium))) \(Text(String(format: Bundle.main.localizedString(forKey: "relays_count", value: nil, table: nil), relays.keys.count)).font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.") let noun_text = Text(verbatim: "\(relaysCountString(relays.keys.count))").font(.subheadline).foregroundColor(.gray)
let relay_text = Text("\(Text("\(relays.keys.count)").font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user { if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
NavigationLink(destination: RelayConfigView(state: damus_state)) { NavigationLink(destination: RelayConfigView(state: damus_state)) {
relay_text relay_text
@@ -443,9 +469,7 @@ struct ProfileView: View {
struct ProfileView_Previews: PreviewProvider { struct ProfileView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let ds = test_damus_state() let ds = test_damus_state()
let followers = FollowersModel(damus_state: ds, target: ds.pubkey) ProfileView(damus_state: ds, pubkey: ds.pubkey)
let profile_model = ProfileModel(pubkey: ds.pubkey, damus: ds)
ProfileView(damus_state: ds, profile: profile_model, followers: followers)
} }
} }
@@ -506,7 +530,7 @@ struct KeyView: View {
.symbolRenderingMode(.palette) .symbolRenderingMode(.palette)
} }
.padding(.leading,4) .padding(.leading,4)
Text(abbrev_pubkey(bech32, amount: 16)) Text(verbatim: "\(abbrev_pubkey(bech32, amount: 16))")
.font(.footnote) .font(.footnote)
.foregroundColor(keyColor()) .foregroundColor(keyColor())
} }

View File

@@ -26,7 +26,7 @@ struct RelayFilterView: View {
} }
var body: some View { var body: some View {
Text("To filter your \(timeline.rawValue) feed, please choose applicable relays from the list below:", comment: "Instructions on how to filter a specific timeline feed by choosing relay servers to filter on.") Text("Please choose relays from the list below to filter the current feed:", comment: "Instructions on how to filter a specific timeline feed by choosing relay servers to filter on.")
.padding() .padding()
.padding(.top, 20) .padding(.top, 20)
.padding(.bottom, 0) .padding(.bottom, 0)

View File

@@ -38,7 +38,7 @@ struct SaveKeysView: View {
.foregroundColor(.white) .foregroundColor(.white)
.padding(.bottom, 10) .padding(.bottom, 10)
Text("This is your account ID, you can give this to your friends so that they can follow you. Click to copy.", comment: "Label to describe that a public key is the user's account ID and what they can do with it.") Text("This is your account ID, you can give this to your friends so that they can follow you. Tap to copy.", comment: "Label to describe that a public key is the user's account ID and what they can do with it.")
.foregroundColor(.white) .foregroundColor(.white)
.padding(.bottom, 10) .padding(.bottom, 10)

View File

@@ -108,6 +108,7 @@ struct SideMenuView: View {
navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), systemImage: "gear") navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), systemImage: "gear")
} }
} }
.labelStyle(SideMenuLabelStyle())
.padding([.top, .bottom], verticalSpacing) .padding([.top, .bottom], verticalSpacing)
} }
} }
@@ -175,6 +176,17 @@ struct SideMenuView: View {
.foregroundColor(textColor()) .foregroundColor(textColor())
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
struct SideMenuLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .center, spacing: 8) {
configuration.icon
.frame(width: 24, height: 24)
.aspectRatio(contentMode: .fit)
configuration.title
}
}
}
} }
struct Previews_SideMenuView_Previews: PreviewProvider { struct Previews_SideMenuView_Previews: PreviewProvider {

View File

@@ -0,0 +1,44 @@
//
// TextViewWrapper.swift
// damus
//
// Created by Swift on 2/24/23.
//
import SwiftUI
struct TextViewWrapper: UIViewRepresentable {
@Binding var attributedText: NSMutableAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.delegate = context.coordinator
textView.font = UIFont.systemFont(ofSize: 18)
textView.textColor = UIColor.label
let linkAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: UIColor(Color.accentColor)]
textView.linkTextAttributes = linkAttributes
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = attributedText
}
func makeCoordinator() -> Coordinator {
Coordinator(attributedText: $attributedText)
}
class Coordinator: NSObject, UITextViewDelegate {
@Binding var attributedText: NSMutableAttributedString
init(attributedText: Binding<NSMutableAttributedString>) {
_attributedText = attributedText
}
func textViewDidChange(_ textView: UITextView) {
attributedText = NSMutableAttributedString(attributedString: textView.attributedText)
}
}
}

View File

@@ -265,6 +265,10 @@ struct ThreadV2View: View {
navigating: $navigating, navigating: $navigating,
selected: false selected: false
) )
Divider()
.padding(.top, 4)
.padding(.leading, 25 * 2)
} }
}.background(GeometryReader { geometry in }.background(GeometryReader { geometry in
// get the height and width of the EventView view // get the height and width of the EventView view
@@ -289,15 +293,20 @@ struct ThreadV2View: View {
).id("main") ).id("main")
// MARK: - Responses of the actual event view // MARK: - Responses of the actual event view
ForEach(thread.childEvents, id: \.id) { event in LazyVStack {
MutedEventView( ForEach(thread.childEvents, id: \.id) { event in
damus_state: damus, MutedEventView(
event: event, damus_state: damus,
scroller: reader, event: event,
nav_target: $nav_target, scroller: nil,
navigating: $navigating, nav_target: $nav_target,
selected: false navigating: $navigating,
) selected: false
)
Divider()
.padding([.top], 4)
}
} }
}.padding() }.padding()
}.navigationBarTitle(NSLocalizedString("Thread", comment: "Navigation bar title for note thread.")) }.navigationBarTitle(NSLocalizedString("Thread", comment: "Navigation bar title for note thread."))

View File

@@ -42,6 +42,9 @@ struct InnerTimelineView: View {
navigating = true navigating = true
} }
.padding(.top, 10) .padding(.top, 10)
Divider()
.padding([.top], 10)
} }
} }
} }

View File

@@ -23,7 +23,7 @@ struct LoadMoreButton: View {
Group { Group {
if events.queued > 0 { if events.queued > 0 {
Button(action: click) { Button(action: click) {
Text("Load \(events.queued) more") Text("Load \(events.queued) more", comment: "Button text for loading more events, where the variable is the number of events.")
} }
.font(.system(size: 14, weight: .bold)) .font(.system(size: 14, weight: .bold))
.padding(10) .padding(10)

View File

@@ -27,17 +27,6 @@ struct TimelineView: View {
MainContent MainContent
} }
func handle_scroll(_ proxy: GeometryProxy) {
let offset = -proxy.frame(in: .named("scroll")).origin.y
guard offset >= 0 else {
return
}
let val = offset > 0
if self.events.should_queue != val {
self.events.should_queue = val
}
}
var realtime_bar_opacity: Double { var realtime_bar_opacity: Double {
colorScheme == .dark ? 0.2 : 0.1 colorScheme == .dark ? 0.2 : 0.1
} }
@@ -55,7 +44,7 @@ struct TimelineView: View {
.disabled(loading) .disabled(loading)
.background(GeometryReader { proxy -> Color in .background(GeometryReader { proxy -> Color in
DispatchQueue.main.async { DispatchQueue.main.async {
handle_scroll(proxy) handle_scroll_queue(proxy, queue: self.events)
} }
return Color.clear return Color.clear
}) })
@@ -82,3 +71,18 @@ struct TimelineView_Previews: PreviewProvider {
} }
protocol ScrollQueue {
var should_queue: Bool { get }
func set_should_queue(_ val: Bool)
}
func handle_scroll_queue(_ proxy: GeometryProxy, queue: ScrollQueue) {
let offset = -proxy.frame(in: .named("scroll")).origin.y
guard offset >= 0 else {
return
}
let val = offset > 0
if queue.should_queue != val {
queue.set_should_queue(val)
}
}

View File

@@ -0,0 +1,215 @@
//
// CustomizeZapView.swift
// damus
//
// Created by William Casarin on 2023-02-25.
//
import SwiftUI
import Combine
enum ZapType {
case pub
case anon
case non_zap
}
struct ZapAmountItem: Identifiable, Hashable {
let amount: Int
let icon: String
var id: String {
return icon
}
}
func get_default_zap_amount_item(_ pubkey: String) -> ZapAmountItem {
let def = get_default_zap_amount(pubkey: pubkey) ?? 1000
return ZapAmountItem(amount: def, icon: "🤙")
}
func get_zap_amount_items(pubkey: String) -> [ZapAmountItem] {
let def_item = get_default_zap_amount_item(pubkey)
var entries = [
ZapAmountItem(amount: 500, icon: "🙂"),
ZapAmountItem(amount: 5000, icon: "💜"),
ZapAmountItem(amount: 10_000, icon: "😍"),
ZapAmountItem(amount: 20_000, icon: "🤩"),
ZapAmountItem(amount: 50_000, icon: "🔥"),
ZapAmountItem(amount: 100_000, icon: "🚀"),
ZapAmountItem(amount: 1_000_000, icon: "🤯"),
]
entries.append(def_item)
entries.sort { $0.amount < $1.amount }
return entries
}
struct CustomizeZapView: View {
let state: DamusState
let event: NostrEvent
let lnurl: String
@State var comment: String
@State var custom_amount: String
@State var custom_amount_sats: Int?
@State var selected_amount: ZapAmountItem
@State var zap_type: ZapType
@State var invoice: String
@State var error: String?
@State var showing_wallet_selector: Bool
@State var zapping: Bool
let zap_amounts: [ZapAmountItem]
@Environment(\.dismiss) var dismiss
init(state: DamusState, event: NostrEvent, lnurl: String) {
self._comment = State(initialValue: "")
self.event = event
self.zap_amounts = get_zap_amount_items(pubkey: state.pubkey)
self._error = State(initialValue: nil)
self._invoice = State(initialValue: "")
self._showing_wallet_selector = State(initialValue: false)
self._custom_amount = State(initialValue: "")
self._zap_type = State(initialValue: .pub)
let selected = get_default_zap_amount_item(state.pubkey)
self._selected_amount = State(initialValue: selected)
self._custom_amount_sats = State(initialValue: nil)
self._zapping = State(initialValue: false)
self.lnurl = lnurl
self.state = state
}
var ZapTypePicker: some View {
Picker(NSLocalizedString("Zap Type", comment: "Header text to indicate that the picker below it is to choose the type of zap to send."), selection: $zap_type) {
Text("Public", comment: "Picker option to indicate that a zap should be sent publicly and identify the user as who sent it.").tag(ZapType.pub)
Text("Anonymous", comment: "Picker option to indicate that a zap should be sent anonymously and not identify the user as who sent it.").tag(ZapType.anon)
Text("Non-Zap", comment: "Picker option to indicate that sats should be sent to the user's wallet as a regular Lightning payment, not as a zap.").tag(ZapType.non_zap)
}
.pickerStyle(.segmented)
}
var AmountPicker: some View {
Picker(NSLocalizedString("Zap Amount", comment: "Title of picker that allows selection of predefined amounts to zap."), selection: $selected_amount) {
ForEach(zap_amounts) { entry in
let fmt = format_msats_abbrev(Int64(entry.amount) * 1000)
HStack(alignment: .firstTextBaseline) {
Text("\(entry.icon)")
.frame(width: 30)
Text("\(fmt)")
.frame(width: 50)
}
.tag(entry)
}
}
.pickerStyle(.wheel)
}
func receive_zap(notif: Notification) {
let zap_ev = notif.object as! ZappingEvent
guard zap_ev.is_custom else {
return
}
guard zap_ev.event.id == event.id else {
return
}
self.zapping = false
switch zap_ev.type {
case .failed(let err):
switch err {
case .fetching_invoice:
self.error = "Error fetching lightning invoice"
case .bad_lnurl:
self.error = "Invalid lightning address"
}
break
case .got_zap_invoice(let inv):
if should_show_wallet_selector(state.pubkey) {
self.invoice = inv
self.showing_wallet_selector = true
} else {
open_with_wallet(wallet: get_default_wallet(state.pubkey).model, invoice: inv)
self.showing_wallet_selector = false
dismiss()
}
}
}
var body: some View {
MainContent
.sheet(isPresented: $showing_wallet_selector) {
SelectWalletView(showingSelectWallet: $showing_wallet_selector, our_pubkey: state.pubkey, invoice: invoice)
}
.onReceive(handle_notify(.zapping)) { notif in
receive_zap(notif: notif)
}
.ignoresSafeArea()
}
var MainContent: some View {
VStack(alignment: .leading) {
Form {
Section(content: {
AmountPicker
}, header: {
Text("Zap Amount in sats", comment: "Header text to indicate that the picker below it is to choose a pre-defined amount of sats to zap.")
})
Section(content: {
TextField(String("100000"), text: $custom_amount)
.keyboardType(.numberPad)
.onReceive(Just(custom_amount)) { newValue in
if let parsed = handle_string_amount(new_value: newValue) {
self.custom_amount = String(parsed)
self.custom_amount_sats = parsed
}
}
}, header: {
Text("Custom Zap Amount", comment: "Header text to indicate that the text field below it is to enter a custom zap amount.")
})
.dismissKeyboardOnTap()
Section(content: {
TextField(NSLocalizedString("Awesome post!", comment: "Placeholder text for a comment to send as part of a zap to the user."), text: $comment)
}, header: {
Text("Comment", comment: "Header text to indicate that the text field below it is a comment that will be used to send as part of a zap to the user.")
})
.dismissKeyboardOnTap()
Section(content: {
ZapTypePicker
}, header: {
Text("Zap Type", comment: "Header text to indicate that the picker below it is to choose the type of zap to send.")
})
if zapping {
Text("Zapping...", comment: "Text to indicate that the app is in the process of sending a zap.")
} else {
Button(NSLocalizedString("Zap", comment: "Button to send a zap.")) {
let amount = custom_amount_sats ?? selected_amount.amount
send_zap(damus_state: state, event: event, lnurl: lnurl, is_custom: true, comment: comment, amount_sats: amount, zap_type: zap_type)
self.zapping = true
}
.zIndex(16)
}
if let error {
Text(error)
.foregroundColor(.red)
}
}
}
}
}
struct CustomizeZapView_Previews: PreviewProvider {
static var previews: some View {
CustomizeZapView(state: test_damus_state(), event: test_event, lnurl: "")
.frame(width: 400, height: 600)
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -4,51 +4,51 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string>%d منشورات اضافية</string>
<key>many</key>
<string>%d منشورات اضافية</string>
<key>one</key>
<string>%d منشور اضافي</string>
<key>other</key>
<string>%d منشورات اضافية</string>
<key>two</key>
<string>%d منشوران</string>
<key>zero</key> <key>zero</key>
<string>%d منشورات أخرى</string> <string>... %d منشورات أخرى ...</string>
<key>one</key>
<string>... %d منشور اضافي ...</string>
<key>two</key>
<string>... %d منشوران ...</string>
<key>few</key>
<string>... %d منشورات اضافية ...</string>
<key>many</key>
<string>... %d منشورات اضافية ...</string>
<key>other</key>
<string>... %d منشورات اضافية ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string>المتابعون</string>
<key>many</key>
<string>المتابعون</string>
<key>one</key>
<string>متابع</string>
<key>other</key>
<string>المتابعون</string>
<key>two</key>
<string>متابعان</string>
<key>zero</key> <key>zero</key>
<string>متابع</string> <string>متابع</string>
<key>one</key>
<string>متابع</string>
<key>two</key>
<string>متابعان</string>
<key>few</key>
<string>المتابِعون</string>
<key>many</key>
<string>المتابِعون</string>
<key>other</key>
<string>المتابِعون</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -60,18 +60,18 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>تفاعل</string>
<key>one</key>
<string>تفاعل</string>
<key>two</key>
<string>تفاعلان</string>
<key>few</key> <key>few</key>
<string>تفاعلات</string> <string>تفاعلات</string>
<key>many</key> <key>many</key>
<string>تفاعل</string> <string>تفاعل</string>
<key>one</key>
<string>تفاعل</string>
<key>other</key> <key>other</key>
<string>تفاعل</string> <string>تفاعل</string>
<key>two</key>
<string>تفاعل</string>
<key>zero</key>
<string>تفاعل</string>
</dict> </dict>
</dict> </dict>
<key>relays_count</key> <key>relays_count</key>
@@ -84,66 +84,66 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>موصّل</string>
<key>one</key>
<string> موصّل</string>
<key>two</key>
<string>موصّلان</string>
<key>few</key> <key>few</key>
<string>موصّلات</string> <string>موصّلات</string>
<key>many</key> <key>many</key>
<string>موصّلات</string> <string>موصّل</string>
<key>one</key>
<string> موصّل</string>
<key>other</key> <key>other</key>
<string>موصّلات</string>
<key>two</key>
<string>موصّلان</string>
<key>zero</key>
<string>موصّل</string> <string>موصّل</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>رد على %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string> &amp; %d آخرون</string>
<key>many</key>
<string> &amp; %d آخرون</string>
<key>one</key>
<string>&amp; %d آخر</string>
<key>other</key>
<string>&amp; %d آخرين</string>
<key>two</key>
<string> &amp; %d آخران</string>
<key>zero</key> <key>zero</key>
<string></string> <string>رد على %2$@</string>
<key>one</key>
<string>الرد على %2$@ &amp; %1$d آخر</string>
<key>two</key>
<string>الرد على %2$@ &amp; %1$d آخرين</string>
<key>few</key>
<string>الرد على %2$@ &amp; %1$d آخرين</string>
<key>many</key>
<string>الرد على %2$@ &amp; %1$d آخرين</string>
<key>other</key>
<string>الرد على %2$@ &amp; %1$d آخرين</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>رد على%@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string> &amp; %d آخرون</string>
<key>many</key>
<string> &amp; %d آخرون</string>
<key>one</key>
<string>&amp; %d آخر</string>
<key>other</key>
<string>&amp; %d آخرين</string>
<key>two</key>
<string> &amp; %d آخران</string>
<key>zero</key> <key>zero</key>
<string></string> <string>الرد على %2$@, %3$@ &amp; %1$d others</string>
<key>one</key>
<string>الرد على %2$@, %3$@ &amp; %1$d آخر</string>
<key>two</key>
<string>الرد على %2$@, %3$@ &amp; %1$d آخرين</string>
<key>few</key>
<string>الرد على %2$@, %3$@ &amp; %1$d آخرين</string>
<key>many</key>
<string>الرد على %2$@, %3$@ &amp; %1$d آخرين</string>
<key>other</key>
<string>الرد على %2$@, %3$@ &amp; %1$d آخرين</string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
@@ -156,18 +156,18 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key> <key>zero</key>
<string>اعادات نشر</string>
<key>many</key>
<string>اعادات نشر</string> <string>اعادات نشر</string>
<key>one</key> <key>one</key>
<string>اعادة نشر</string> <string>اعادة نشر</string>
<key>other</key>
<string>اعادات نشر</string>
<key>two</key> <key>two</key>
<string>اعادتا نشر</string>
<key>few</key>
<string>اعادات نشر</string> <string>اعادات نشر</string>
<key>zero</key> <key>many</key>
<string>اعادات نشر</string> <string>اعادة نشر</string>
<key>other</key>
<string>اعادة نشر</string>
</dict> </dict>
</dict> </dict>
<key>sats_count</key> <key>sats_count</key>
@@ -180,18 +180,18 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>@</string> <string>@</string>
<key>zero</key>
<string>%2$@ ساتوشي</string>
<key>one</key>
<string>%2$@ ساتوشي</string>
<key>two</key>
<string>%2$@ ساتوشي</string>
<key>few</key> <key>few</key>
<string>%2$@ ساتوشي</string> <string>%2$@ ساتوشي</string>
<key>many</key> <key>many</key>
<string>%2$@ ساتوشي</string> <string>%2$@ ساتوشي</string>
<key>one</key>
<string>%2$@ ساتوشي</string>
<key>other</key> <key>other</key>
<string>%2$@ ساتوشي</string> <string>%2$@ ساتوشي</string>
<key>two</key>
<string>%2$@ ساتوشي</string>
<key>zero</key>
<string>%2$@ ساتوشي</string>
</dict> </dict>
</dict> </dict>
<key>zaps_count</key> <key>zaps_count</key>
@@ -204,18 +204,18 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key> <key>zero</key>
<string>وميض</string>
<key>many</key>
<string>وميض</string> <string>وميض</string>
<key>one</key> <key>one</key>
<string>ومضة</string> <string>ومضة</string>
<key>other</key>
<string>وميض</string>
<key>two</key> <key>two</key>
<string>وميض</string> <string>ومضتان</string>
<key>zero</key> <key>few</key>
<string>وميض</string> <string>ومضات</string>
<key>many</key>
<string>ومضة</string>
<key>other</key>
<string>ومضة</string>
</dict> </dict>
</dict> </dict>
</dict> </dict>

Binary file not shown.

Binary file not shown.

View File

@@ -4,43 +4,43 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string>%d other notes</string>
<key>many</key>
<string>%d other notes</string>
<key>one</key> <key>one</key>
<string>%d jiná poznámka</string> <string>... %d jiná poznámka ...</string>
<key>few</key>
<string>... %d other notes ...</string>
<key>many</key>
<string>... %d other notes ...</string>
<key>other</key> <key>other</key>
<string>%d jiné poznámky</string> <string>... %d jiné poznámky ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>Seguidor</string>
<key>few</key> <key>few</key>
<string>Followers</string> <string>Followers</string>
<key>many</key> <key>many</key>
<string>Followers</string> <string>Followers</string>
<key>one</key>
<string>Seguidor</string>
<key>other</key> <key>other</key>
<string>Sledují</string> <string>Sledují</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -52,12 +52,12 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>Reakce</string>
<key>few</key> <key>few</key>
<string>Reactions</string> <string>Reactions</string>
<key>many</key> <key>many</key>
<string>Reactions</string> <string>Reactions</string>
<key>one</key>
<string>Reakce</string>
<key>other</key> <key>other</key>
<string>Reakce</string> <string>Reakce</string>
</dict> </dict>
@@ -72,12 +72,12 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>Relé</string>
<key>few</key> <key>few</key>
<string>Relays</string> <string>Relays</string>
<key>many</key> <key>many</key>
<string>Relays</string> <string>Relays</string>
<key>one</key>
<string>Relé</string>
<key>other</key> <key>other</key>
<string>Relé</string> <string>Relé</string>
</dict> </dict>
@@ -85,45 +85,41 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Odpověď na %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string> &amp; %d others</string>
<key>many</key>
<string> &amp; %d others</string>
<key>one</key> <key>one</key>
<string> a %d další</string> <string>Odpověď na %2$@ a %1$d další</string>
<key>few</key>
<string>Odpověď na %2$@ a %1$d others</string>
<key>many</key>
<string>Odpověď na %2$@ a %1$d others</string>
<key>other</key> <key>other</key>
<string> a %d další</string> <string>Odpověď na %2$@ a %1$d další</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Odpovědět na %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>few</key>
<string> &amp; %d others</string>
<key>many</key>
<string> &amp; %d others</string>
<key>one</key> <key>one</key>
<string> a %d další</string> <string>Odpovědět na %2$@, %3$@ &amp; %1$d další</string>
<key>few</key>
<string>Odpovědět na %2$@, %3$@ &amp; %1$d others</string>
<key>many</key>
<string>Odpovědět na %2$@, %3$@ &amp; %1$d others</string>
<key>other</key> <key>other</key>
<string> a %d další</string> <string>Odpovědět na %2$@, %3$@ &amp; %1$d další</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
@@ -136,12 +132,12 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>Přesdílet</string>
<key>few</key> <key>few</key>
<string>Reposts</string> <string>Reposts</string>
<key>many</key> <key>many</key>
<string>Reposts</string> <string>Reposts</string>
<key>one</key>
<string>Přesdílet</string>
<key>other</key> <key>other</key>
<string>Přesdílené </string> <string>Přesdílené </string>
</dict> </dict>
@@ -156,12 +152,12 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>@</string> <string>@</string>
<key>one</key>
<string>%2$@ sat</string>
<key>few</key> <key>few</key>
<string>%2$@ sats</string> <string>%2$@ sats</string>
<key>many</key> <key>many</key>
<string>%2$@ sats</string> <string>%2$@ sats</string>
<key>one</key>
<string>%2$@ sat</string>
<key>other</key> <key>other</key>
<string>%2$@ satů</string> <string>%2$@ satů</string>
</dict> </dict>
@@ -176,12 +172,12 @@
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>Zap</string>
<key>few</key> <key>few</key>
<string>Zaps</string> <string>Zaps</string>
<key>many</key> <key>many</key>
<string>Zaps</string> <string>Zaps</string>
<key>one</key>
<string>Zap</string>
<key>other</key> <key>other</key>
<string>Zapů</string> <string>Zapů</string>
</dict> </dict>

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d andere Notiz</string> <string>... %d andere Notiz ...</string>
<key>other</key> <key>other</key>
<string>%d andere Notizen</string> <string>... %d andere Notizen ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -31,8 +33,6 @@
<key>other</key> <key>other</key>
<string>Follower</string> <string>Follower</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -69,7 +69,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Antwort an %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +77,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d andere</string> <string>Antwort an %2$@ &amp; %1$d andere</string>
<key>other</key> <key>other</key>
<string> &amp; %d andere</string> <string>Antwort an %2$@ &amp; %1$d andere</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Antwort an %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +93,9 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d andere</string> <string>Antwort an %2$@, %3$@ &amp; %1$d andere</string>
<key>other</key> <key>other</key>
<string> &amp; %d andere</string> <string>Antwort an %2$@, %3$@ &amp; %1$d andere</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d άλλη σημείωση</string> <string>... %d άλλη σημείωση ...</string>
<key>other</key> <key>other</key>
<string>%d άλλες σημειώσεις</string> <string>... %d άλλες σημειώσεις ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -31,8 +33,6 @@
<key>other</key> <key>other</key>
<string>Ακόλουθοι</string> <string>Ακόλουθοι</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -69,7 +69,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Απάντηση προς %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +77,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d άλλον</string> <string>Replying to %2$@ &amp; %1$d other</string>
<key>other</key> <key>other</key>
<string> &amp; %d άλλους</string> <string>Replying to %2$@ &amp; %1$d others</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Απάντηση προς %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +93,9 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d άλλον</string> <string>Απάντηση προς %2$@, %3$@ &amp; %1$d άλλον</string>
<key>other</key> <key>other</key>
<string> &amp; %d άλλους</string> <string>Απάντηση προς %2$@, %3$@ &amp; %1$d άλλους</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>

Binary file not shown.

View File

@@ -34,6 +34,54 @@
<string>Followers</string> <string>Followers</string>
</dict> </dict>
</dict> </dict>
<key>reacted_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to a post you were tagged in</string>
</dict>
</dict>
<key>reacted_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to your post</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to your post</string>
</dict>
</dict>
<key>reacted_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to your profile</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to your profile</string>
</dict>
</dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -66,22 +114,6 @@
<string>Relays</string> <string>Relays</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_one_and_others</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@OTHERS@</string>
<key>OTHERS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Replying to %2$@ &amp; %1$d other</string>
<key>other</key>
<string>Replying to %2$@ &amp; %1$d others</string>
</dict>
</dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -98,6 +130,54 @@
<string>Replying to %2$@, %3$@ &amp; %1$d others</string> <string>Replying to %2$@, %3$@ &amp; %1$d others</string>
</dict> </dict>
</dict> </dict>
<key>reposted_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others reposted a post you were tagged in</string>
</dict>
</dict>
<key>reposted_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted your post</string>
<key>other</key>
<string>%2$@ and %1$d others reposted your post</string>
</dict>
</dict>
<key>reposted_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted your profile</string>
<key>other</key>
<string>%2$@ and %1$d others reposted your profile</string>
</dict>
</dict>
<key>reposts_count</key> <key>reposts_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -130,6 +210,54 @@
<string>%2$@ sats</string> <string>%2$@ sats</string>
</dict> </dict>
</dict> </dict>
<key>zapped_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others zapped a post you were tagged in</string>
</dict>
</dict>
<key>zapped_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped your post</string>
<key>other</key>
<string>%2$@ and %1$d others zapped your post</string>
</dict>
</dict>
<key>zapped_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped your profile</string>
<key>other</key>
<string>%2$@ and %1$d others zapped your profile</string>
</dict>
</dict>
<key>zaps_count</key> <key>zaps_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>

View File

@@ -32,6 +32,11 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/> <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header> </header>
<body> <body>
<trans-unit id="%@" xml:space="preserve">
<source>%@</source>
<target>%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ %@" xml:space="preserve"> <trans-unit id="%@ %@" xml:space="preserve">
<source>%@ %@</source> <source>%@ %@</source>
<target>%@ %@</target> <target>%@ %@</target>
@@ -58,6 +63,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet.</target> <target>%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet.</target>
<note>Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string.</note> <note>Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld" xml:space="preserve">
<source>%lld</source>
<target>%lld</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld/%lld" xml:space="preserve"> <trans-unit id="%lld/%lld" xml:space="preserve">
<source>%lld/%lld</source> <source>%lld/%lld</source>
<target>%lld/%lld</target> <target>%lld/%lld</target>
@@ -73,15 +83,10 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>'%@' is an invalid NIP-05 identifier. It should look like an email.</target> <target>'%@' is an invalid NIP-05 identifier. It should look like an email.</target>
<note>Description of why the nip05 identifier is invalid.</note> <note>Description of why the nip05 identifier is invalid.</note>
</trans-unit> </trans-unit>
<trans-unit id="(Profile.displayName(profile: profile, pubkey: whos))'s Followers" xml:space="preserve"> <trans-unit id="??" xml:space="preserve">
<source>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</source> <source>??</source>
<target>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</target> <target>??</target>
<note>Navigation bar title for view that shows who is following a user.</note> <note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(who) following" xml:space="preserve">
<source>(who) following</source>
<target>(who) following</target>
<note>Navigation bar title for view that shows who a user is following.</note>
</trans-unit> </trans-unit>
<trans-unit id="API Key (optional)" xml:space="preserve"> <trans-unit id="API Key (optional)" xml:space="preserve">
<source>API Key (optional)</source> <source>API Key (optional)</source>
@@ -129,6 +134,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<note>Button to add recommended relay server. <note>Button to add recommended relay server.
Button to confirm adding user inputted relay.</note> Button to confirm adding user inputted relay.</note>
</trans-unit> </trans-unit>
<trans-unit id="Add Bookmark" xml:space="preserve">
<source>Add Bookmark</source>
<target>Add Bookmark</target>
<note>Context menu option for adding a note bookmark.</note>
</trans-unit>
<trans-unit id="Add Relay" xml:space="preserve"> <trans-unit id="Add Relay" xml:space="preserve">
<source>Add Relay</source> <source>Add Relay</source>
<target>Add Relay</target> <target>Add Relay</target>
@@ -144,6 +154,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Admin</target> <target>Admin</target>
<note>Label to display relay contact user.</note> <note>Label to display relay contact user.</note>
</trans-unit> </trans-unit>
<trans-unit id="Anonymous" xml:space="preserve">
<source>Anonymous</source>
<target>Anonymous</target>
<note>Picker option to indicate that a zap should be sent anonymously and not identify the user as who sent it.</note>
</trans-unit>
<trans-unit id="Any" xml:space="preserve"> <trans-unit id="Any" xml:space="preserve">
<source>Any</source> <source>Any</source>
<target>Any</target> <target>Any</target>
@@ -154,6 +169,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Are you sure you want to repost this?</target> <target>Are you sure you want to repost this?</target>
<note>Alert message to ask if user wants to repost a post.</note> <note>Alert message to ask if user wants to repost a post.</note>
</trans-unit> </trans-unit>
<trans-unit id="Awesome post!" xml:space="preserve">
<source>Awesome post!</source>
<target>Awesome post!</target>
<note>Placeholder text for a comment to send as part of a zap to the user.</note>
</trans-unit>
<trans-unit id="Banner Image" xml:space="preserve"> <trans-unit id="Banner Image" xml:space="preserve">
<source>Banner Image</source> <source>Banner Image</source>
<target>Banner Image</target> <target>Banner Image</target>
@@ -211,6 +231,12 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Blue Wallet</target> <target>Blue Wallet</target>
<note>Dropdown option label for Lightning wallet, Blue Wallet.</note> <note>Dropdown option label for Lightning wallet, Blue Wallet.</note>
</trans-unit> </trans-unit>
<trans-unit id="Bookmarks" xml:space="preserve">
<source>Bookmarks</source>
<target>Bookmarks</target>
<note>Sidebar menu label for Bookmarks view.
Title of bookmarks view</note>
</trans-unit>
<trans-unit id="Boosts" xml:space="preserve"> <trans-unit id="Boosts" xml:space="preserve">
<source>Boosts</source> <source>Boosts</source>
<target>Boosts</target> <target>Boosts</target>
@@ -247,11 +273,21 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Clear</target> <target>Clear</target>
<note>Button for clearing cached data.</note> <note>Button for clearing cached data.</note>
</trans-unit> </trans-unit>
<trans-unit id="Clear All" xml:space="preserve">
<source>Clear All</source>
<target>Clear All</target>
<note>Button for clearing bookmarks data.</note>
</trans-unit>
<trans-unit id="Clear Cache" xml:space="preserve"> <trans-unit id="Clear Cache" xml:space="preserve">
<source>Clear Cache</source> <source>Clear Cache</source>
<target>Clear Cache</target> <target>Clear Cache</target>
<note>Section title for clearing cached data.</note> <note>Section title for clearing cached data.</note>
</trans-unit> </trans-unit>
<trans-unit id="Comment" xml:space="preserve">
<source>Comment</source>
<target>Comment</target>
<note>Header text to indicate that the text field below it is a comment that will be used to send as part of a zap to the user.</note>
</trans-unit>
<trans-unit id="Contact" xml:space="preserve"> <trans-unit id="Contact" xml:space="preserve">
<source>Contact</source> <source>Contact</source>
<target>Contact</target> <target>Contact</target>
@@ -348,6 +384,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Custom</target> <target>Custom</target>
<note>Dropdown option for selecting a custom translation server.</note> <note>Dropdown option for selecting a custom translation server.</note>
</trans-unit> </trans-unit>
<trans-unit id="Custom Zap Amount" xml:space="preserve">
<source>Custom Zap Amount</source>
<target>Custom Zap Amount</target>
<note>Header text to indicate that the text field below it is to enter a custom zap amount.</note>
</trans-unit>
<trans-unit id="DMs" xml:space="preserve"> <trans-unit id="DMs" xml:space="preserve">
<source>DMs</source> <source>DMs</source>
<target>DMs</target> <target>DMs</target>
@@ -470,12 +511,12 @@ Sentence composed of 2 variables to describe how many people are following a use
<trans-unit id="Followers" xml:space="preserve"> <trans-unit id="Followers" xml:space="preserve">
<source>Followers</source> <source>Followers</source>
<target>Followers</target> <target>Followers</target>
<note>Label describing followers of a user.</note> <note>Navigation bar title for view that shows who is following a user.</note>
</trans-unit> </trans-unit>
<trans-unit id="Following" xml:space="preserve"> <trans-unit id="Following" xml:space="preserve">
<source>Following</source> <source>Following</source>
<target>Following</target> <target>Following</target>
<note>Part of a larger sentence to describe how many profiles a user is following.</note> <note>Navigation bar title for view that shows who a user is following.</note>
</trans-unit> </trans-unit>
<trans-unit id="Following..." xml:space="preserve"> <trans-unit id="Following..." xml:space="preserve">
<source>Following...</source> <source>Following...</source>
@@ -573,6 +614,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Like</target> <target>Like</target>
<note>Accessibility Label for Like button</note> <note>Accessibility Label for Like button</note>
</trans-unit> </trans-unit>
<trans-unit id="Load %lld more" xml:space="preserve">
<source>Load %lld more</source>
<target>Load %lld more</target>
<note>Button text for loading more events, where the variable is the number of events.</note>
</trans-unit>
<trans-unit id="Local authentication to access private key" xml:space="preserve"> <trans-unit id="Local authentication to access private key" xml:space="preserve">
<source>Local authentication to access private key</source> <source>Local authentication to access private key</source>
<target>Local authentication to access private key</target> <target>Local authentication to access private key</target>
@@ -621,6 +667,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>No block list found, create a new one? This will overwrite any previous block lists.</target> <target>No block list found, create a new one? This will overwrite any previous block lists.</target>
<note>Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists.</note> <note>Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists.</note>
</trans-unit> </trans-unit>
<trans-unit id="Non-Zap" xml:space="preserve">
<source>Non-Zap</source>
<target>Non-Zap</target>
<note>Picker option to indicate that sats should be sent to the user's wallet as a regular Lightning payment, not as a zap.</note>
</trans-unit>
<trans-unit id="None" xml:space="preserve"> <trans-unit id="None" xml:space="preserve">
<source>None</source> <source>None</source>
<target>None</target> <target>None</target>
@@ -676,6 +727,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Plan</target> <target>Plan</target>
<note>Prompt selection of DeepL subscription plan to perform machine translations on notes</note> <note>Prompt selection of DeepL subscription plan to perform machine translations on notes</note>
</trans-unit> </trans-unit>
<trans-unit id="Please choose relays from the list below to filter the current feed:" xml:space="preserve">
<source>Please choose relays from the list below to filter the current feed:</source>
<target>Please choose relays from the list below to filter the current feed:</target>
<note>Instructions on how to filter a specific timeline feed by choosing relay servers to filter on.</note>
</trans-unit>
<trans-unit id="Post" xml:space="preserve"> <trans-unit id="Post" xml:space="preserve">
<source>Post</source> <source>Post</source>
<target>Post</target> <target>Post</target>
@@ -723,6 +779,11 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Profile Picture</target> <target>Profile Picture</target>
<note>Label for Profile Picture section of user profile form.</note> <note>Label for Profile Picture section of user profile form.</note>
</trans-unit> </trans-unit>
<trans-unit id="Public" xml:space="preserve">
<source>Public</source>
<target>Public</target>
<note>Picker option to indicate that a zap should be sent publicly and identify the user as who sent it.</note>
</trans-unit>
<trans-unit id="Public Account ID" xml:space="preserve"> <trans-unit id="Public Account ID" xml:space="preserve">
<source>Public Account ID</source> <source>Public Account ID</source>
<target>Public Account ID</target> <target>Public Account ID</target>
@@ -774,6 +835,11 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Relays have been notified and clients will be able to use this information to filter content. Thank you!</target> <target>Relays have been notified and clients will be able to use this information to filter content. Thank you!</target>
<note>Description of what was done as a result of sending a report to relay servers.</note> <note>Description of what was done as a result of sending a report to relay servers.</note>
</trans-unit> </trans-unit>
<trans-unit id="Remove Bookmark" xml:space="preserve">
<source>Remove Bookmark</source>
<target>Remove Bookmark</target>
<note>Context menu option for removing a note bookmark.</note>
</trans-unit>
<trans-unit id="Remove all" xml:space="preserve"> <trans-unit id="Remove all" xml:space="preserve">
<source>Remove all</source> <source>Remove all</source>
<target>Remove all</target> <target>Remove all</target>
@@ -986,9 +1052,9 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key.</target> <target>This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key.</target>
<note>Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key.</note> <note>Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key.</note>
</trans-unit> </trans-unit>
<trans-unit id="This is your account ID, you can give this to your friends so that they can follow you. Click to copy." xml:space="preserve"> <trans-unit id="This is your account ID, you can give this to your friends so that they can follow you. Tap to copy." xml:space="preserve">
<source>This is your account ID, you can give this to your friends so that they can follow you. Click to copy.</source> <source>This is your account ID, you can give this to your friends so that they can follow you. Tap to copy.</source>
<target>This is your account ID, you can give this to your friends so that they can follow you. Click to copy.</target> <target>This is your account ID, you can give this to your friends so that they can follow you. Tap to copy.</target>
<note>Label to describe that a public key is the user's account ID and what they can do with it.</note> <note>Label to describe that a public key is the user's account ID and what they can do with it.</note>
</trans-unit> </trans-unit>
<trans-unit id="This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" xml:space="preserve"> <trans-unit id="This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" xml:space="preserve">
@@ -1001,11 +1067,6 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Thread</target> <target>Thread</target>
<note>Navigation bar title for note thread.</note> <note>Navigation bar title for note thread.</note>
</trans-unit> </trans-unit>
<trans-unit id="To filter your %@ feed, please choose applicable relays from the list below:" xml:space="preserve">
<source>To filter your %@ feed, please choose applicable relays from the list below:</source>
<target>To filter your %@ feed, please choose applicable relays from the list below:</target>
<note>Instructions on how to filter a specific timeline feed by choosing relay servers to filter on.</note>
</trans-unit>
<trans-unit id="Translate Note" xml:space="preserve"> <trans-unit id="Translate Note" xml:space="preserve">
<source>Translate Note</source> <source>Translate Note</source>
<target>Translate Note</target> <target>Translate Note</target>
@@ -1123,6 +1184,11 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Yes, Post with Private Key</target> <target>Yes, Post with Private Key</target>
<note>Button to proceed with posting a note even though it looks like they might be posting a private key.</note> <note>Button to proceed with posting a note even though it looks like they might be posting a private key.</note>
</trans-unit> </trans-unit>
<trans-unit id="You have no bookmarks yet, add them in the context menu" xml:space="preserve">
<source>You have no bookmarks yet, add them in the context menu</source>
<target>You have no bookmarks yet, add them in the context menu</target>
<note>Text indicating that there are no bookmarks to be viewed</note>
</trans-unit>
<trans-unit id="Your Name" xml:space="preserve"> <trans-unit id="Your Name" xml:space="preserve">
<source>Your Name</source> <source>Your Name</source>
<target>Your Name</target> <target>Your Name</target>
@@ -1136,7 +1202,28 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<trans-unit id="Zap" xml:space="preserve"> <trans-unit id="Zap" xml:space="preserve">
<source>Zap</source> <source>Zap</source>
<target>Zap</target> <target>Zap</target>
<note>Accessibility label for zap button</note> <note>Accessibility label for zap button
Button to send a zap.</note>
</trans-unit>
<trans-unit id="Zap Amount" xml:space="preserve">
<source>Zap Amount</source>
<target>Zap Amount</target>
<note>Title of picker that allows selection of predefined amounts to zap.</note>
</trans-unit>
<trans-unit id="Zap Amount in sats" xml:space="preserve">
<source>Zap Amount in sats</source>
<target>Zap Amount in sats</target>
<note>Header text to indicate that the picker below it is to choose a pre-defined amount of sats to zap.</note>
</trans-unit>
<trans-unit id="Zap Type" xml:space="preserve">
<source>Zap Type</source>
<target>Zap Type</target>
<note>Header text to indicate that the picker below it is to choose the type of zap to send.</note>
</trans-unit>
<trans-unit id="Zapping..." xml:space="preserve">
<source>Zapping...</source>
<target>Zapping...</target>
<note>Text to indicate that the app is in the process of sending a zap.</note>
</trans-unit> </trans-unit>
<trans-unit id="Zaps" xml:space="preserve"> <trans-unit id="Zaps" xml:space="preserve">
<source>Zaps</source> <source>Zaps</source>
@@ -1188,6 +1275,66 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>optional</target> <target>optional</target>
<note>Label indicating that a form input is optional.</note> <note>Label indicating that a form input is optional.</note>
</trans-unit> </trans-unit>
<trans-unit id="reacted_tagged_in_1" xml:space="preserve">
<source>%@ reacted to a post you were tagged in</source>
<target>%@ reacted to a post you were tagged in</target>
<note>Notification that a user reacted to a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="reacted_tagged_in_2" xml:space="preserve">
<source>%@ and %@ reacted to a post you were tagged in</source>
<target>%@ and %@ reacted to a post you were tagged in</target>
<note>Notification that 2 users reacted to a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="reacted_your_post_1" xml:space="preserve">
<source>%@ reacted to your post</source>
<target>%@ reacted to your post</target>
<note>Notification that a user reacted to the current user's post</note>
</trans-unit>
<trans-unit id="reacted_your_post_2" xml:space="preserve">
<source>%@ and %@ reacted to your post</source>
<target>%@ and %@ reacted to your post</target>
<note>Notification that 2 users reacted to the current user's profile</note>
</trans-unit>
<trans-unit id="reacted_your_profile_1" xml:space="preserve">
<source>%@ reacted to your profile</source>
<target>%@ reacted to your profile</target>
<note>Notification that a user reacted to the current user's profile</note>
</trans-unit>
<trans-unit id="reacted_your_profile_2" xml:space="preserve">
<source>%@ and %@ reacted to your profile</source>
<target>%@ and %@ reacted to your profile</target>
<note>Notification that 2 users reacted to the current user's profile</note>
</trans-unit>
<trans-unit id="reposted_tagged_in_1" xml:space="preserve">
<source>%@ reposted a post you were tagged in</source>
<target>%@ reposted a post you were tagged in</target>
<note>Notification that a user reposted a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="reposted_tagged_in_2" xml:space="preserve">
<source>%@ and %@ reposted a post you were tagged in</source>
<target>%@ and %@ reposted a post you were tagged in</target>
<note>Notification that 2 users reposted a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="reposted_your_post_1" xml:space="preserve">
<source>%@ reposted your post</source>
<target>%@ reposted your post</target>
<note>Notification that a user reposted the current user's post</note>
</trans-unit>
<trans-unit id="reposted_your_post_2" xml:space="preserve">
<source>%@ and %@ reposted your post</source>
<target>%@ and %@ reposted your post</target>
<note>Notification that 2 users reposted the current user's post</note>
</trans-unit>
<trans-unit id="reposted_your_profile_1" xml:space="preserve">
<source>%@ reposted your profile</source>
<target>%@ reposted your profile</target>
<note>Notification that a user reposted the current user's profile</note>
</trans-unit>
<trans-unit id="reposted_your_profile_2" xml:space="preserve">
<source>%@ and %@ reposted your profile</source>
<target>%@ and %@ reposted your profile</target>
<note>Notification that 2 users reposted the current user's profile</note>
</trans-unit>
<trans-unit id="satoshi" xml:space="preserve"> <trans-unit id="satoshi" xml:space="preserve">
<source>satoshi</source> <source>satoshi</source>
<target>satoshi</target> <target>satoshi</target>
@@ -1203,6 +1350,36 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>you</target> <target>you</target>
<note>You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself.</note> <note>You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself.</note>
</trans-unit> </trans-unit>
<trans-unit id="zapped_tagged_in_1" xml:space="preserve">
<source>%@ zapped a post you were tagged in</source>
<target>%@ zapped a post you were tagged in</target>
<note>Notification that a user zapped a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="zapped_tagged_in_2" xml:space="preserve">
<source>%@ and %@ zapped a post you were tagged in</source>
<target>%@ and %@ zapped a post you were tagged in</target>
<note>Notification that 2 users zapped a post that the current user was tagged in</note>
</trans-unit>
<trans-unit id="zapped_your_post_1" xml:space="preserve">
<source>%@ zapped your post</source>
<target>%@ zapped your post</target>
<note>Notification that a user zapped the current user's post</note>
</trans-unit>
<trans-unit id="zapped_your_post_2" xml:space="preserve">
<source>%@ and %@ zapped your post</source>
<target>%@ and %@ zapped your post</target>
<note>Notification that 2 users zapped the current user's post</note>
</trans-unit>
<trans-unit id="zapped_your_profile_1" xml:space="preserve">
<source>%@ zapped your profile</source>
<target>%@ zapped your profile</target>
<note>Notification that a user zapped the current user's profile</note>
</trans-unit>
<trans-unit id="zapped_your_profile_2" xml:space="preserve">
<source>%@ and %@ zapped your profile</source>
<target>%@ and %@ zapped your profile</target>
<note>Notification that 2 users zapped the current user's profile</note>
</trans-unit>
<trans-unit id="⚡️ %@" xml:space="preserve"> <trans-unit id="⚡️ %@" xml:space="preserve">
<source>⚡️ %@</source> <source>⚡️ %@</source>
<target>⚡️ %@</target> <target>⚡️ %@</target>
@@ -1245,6 +1422,51 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>%#@FOLLOWERS@</target> <target>%#@FOLLOWERS@</target>
<note/> <note/>
</trans-unit> </trans-unit>
<trans-unit id="/reacted_tagged_in_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REACTED@</source>
<target>%#@REACTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_tagged_in_3:dict/REACTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reacted to a post you were tagged in</source>
<target>%2$@ and %1$d other reacted to a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_tagged_in_3:dict/REACTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reacted to a post you were tagged in</source>
<target>%2$@ and %1$d others reacted to a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_post_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REACTED@</source>
<target>%#@REACTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_post_3:dict/REACTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reacted to your post</source>
<target>%2$@ and %1$d other reacted to your post</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_post_3:dict/REACTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reacted to your post</source>
<target>%2$@ and %1$d others reacted to your post</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_profile_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REACTED@</source>
<target>%#@REACTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_profile_3:dict/REACTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reacted to your profile</source>
<target>%2$@ and %1$d other reacted to your profile</target>
<note/>
</trans-unit>
<trans-unit id="/reacted_your_profile_3:dict/REACTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reacted to your profile</source>
<target>%2$@ and %1$d others reacted to your profile</target>
<note/>
</trans-unit>
<trans-unit id="/reactions_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve"> <trans-unit id="/reactions_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REACTIONS@</source> <source>%#@REACTIONS@</source>
<target>%#@REACTIONS@</target> <target>%#@REACTIONS@</target>
@@ -1275,21 +1497,6 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Relays</target> <target>Relays</target>
<note/> <note/>
</trans-unit> </trans-unit>
<trans-unit id="/replying_to_one_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@OTHERS@</source>
<target>%#@OTHERS@</target>
<note/>
</trans-unit>
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
<source>Replying to %2$@ &amp; %1$d other</source>
<target>Replying to %2$@ &amp; %1$d other</target>
<note/>
</trans-unit>
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
<source>Replying to %2$@ &amp; %1$d others</source>
<target>Replying to %2$@ &amp; %1$d others</target>
<note/>
</trans-unit>
<trans-unit id="/replying_to_two_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve"> <trans-unit id="/replying_to_two_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@OTHERS@</source> <source>%#@OTHERS@</source>
<target>%#@OTHERS@</target> <target>%#@OTHERS@</target>
@@ -1305,6 +1512,51 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>Replying to %2$@, %3$@ &amp; %1$d others</target> <target>Replying to %2$@, %3$@ &amp; %1$d others</target>
<note/> <note/>
</trans-unit> </trans-unit>
<trans-unit id="/reposted_tagged_in_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REPOSTED@</source>
<target>%#@REPOSTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_tagged_in_3:dict/REPOSTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reposted a post you were tagged in</source>
<target>%2$@ and %1$d other reposted a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_tagged_in_3:dict/REPOSTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reposted a post you were tagged in</source>
<target>%2$@ and %1$d others reposted a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_post_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REPOSTED@</source>
<target>%#@REPOSTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_post_3:dict/REPOSTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reposted your post</source>
<target>%2$@ and %1$d other reposted your post</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_post_3:dict/REPOSTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reposted your post</source>
<target>%2$@ and %1$d others reposted your post</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_profile_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REPOSTED@</source>
<target>%#@REPOSTED@</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_profile_3:dict/REPOSTED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other reposted your profile</source>
<target>%2$@ and %1$d other reposted your profile</target>
<note/>
</trans-unit>
<trans-unit id="/reposted_your_profile_3:dict/REPOSTED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others reposted your profile</source>
<target>%2$@ and %1$d others reposted your profile</target>
<note/>
</trans-unit>
<trans-unit id="/reposts_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve"> <trans-unit id="/reposts_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@REPOSTS@</source> <source>%#@REPOSTS@</source>
<target>%#@REPOSTS@</target> <target>%#@REPOSTS@</target>
@@ -1335,6 +1587,51 @@ Label for filter for seeing your posts and replies (instead of only your posts).
<target>%2$@ sats</target> <target>%2$@ sats</target>
<note/> <note/>
</trans-unit> </trans-unit>
<trans-unit id="/zapped_tagged_in_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@ZAPPED@</source>
<target>%#@ZAPPED@</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_tagged_in_3:dict/ZAPPED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other zapped a post you were tagged in</source>
<target>%2$@ and %1$d other zapped a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_tagged_in_3:dict/ZAPPED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others zapped a post you were tagged in</source>
<target>%2$@ and %1$d others zapped a post you were tagged in</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_post_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@ZAPPED@</source>
<target>%#@ZAPPED@</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_post_3:dict/ZAPPED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other zapped your post</source>
<target>%2$@ and %1$d other zapped your post</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_post_3:dict/ZAPPED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others zapped your post</source>
<target>%2$@ and %1$d others zapped your post</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_profile_3:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@ZAPPED@</source>
<target>%#@ZAPPED@</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_profile_3:dict/ZAPPED:dict/one:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d other zapped your profile</source>
<target>%2$@ and %1$d other zapped your profile</target>
<note/>
</trans-unit>
<trans-unit id="/zapped_your_profile_3:dict/ZAPPED:dict/other:dict/:string" xml:space="preserve">
<source>%2$@ and %1$d others zapped your profile</source>
<target>%2$@ and %1$d others zapped your profile</target>
<note/>
</trans-unit>
<trans-unit id="/zaps_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve"> <trans-unit id="/zaps_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@ZAPS@</source> <source>%#@ZAPS@</source>
<target>%#@ZAPS@</target> <target>%#@ZAPS@</target>

View File

@@ -34,6 +34,54 @@
<string>Followers</string> <string>Followers</string>
</dict> </dict>
</dict> </dict>
<key>reacted_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to a post you were tagged in</string>
</dict>
</dict>
<key>reacted_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to your post</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to your post</string>
</dict>
</dict>
<key>reacted_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REACTED@</string>
<key>REACTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reacted to your profile</string>
<key>other</key>
<string>%2$@ and %1$d others reacted to your profile</string>
</dict>
</dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -66,22 +114,6 @@
<string>Relays</string> <string>Relays</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_one_and_others</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@OTHERS@</string>
<key>OTHERS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Replying to %2$@ &amp; %1$d other</string>
<key>other</key>
<string>Replying to %2$@ &amp; %1$d others</string>
</dict>
</dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -98,6 +130,54 @@
<string>Replying to %2$@, %3$@ &amp; %1$d others</string> <string>Replying to %2$@, %3$@ &amp; %1$d others</string>
</dict> </dict>
</dict> </dict>
<key>reposted_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others reposted a post you were tagged in</string>
</dict>
</dict>
<key>reposted_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted your post</string>
<key>other</key>
<string>%2$@ and %1$d others reposted your post</string>
</dict>
</dict>
<key>reposted_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@REPOSTED@</string>
<key>REPOSTED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other reposted your profile</string>
<key>other</key>
<string>%2$@ and %1$d others reposted your profile</string>
</dict>
</dict>
<key>reposts_count</key> <key>reposts_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -130,6 +210,54 @@
<string>%2$@ sats</string> <string>%2$@ sats</string>
</dict> </dict>
</dict> </dict>
<key>zapped_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped a post you were tagged in</string>
<key>other</key>
<string>%2$@ and %1$d others zapped a post you were tagged in</string>
</dict>
</dict>
<key>zapped_your_post_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped your post</string>
<key>other</key>
<string>%2$@ and %1$d others zapped your post</string>
</dict>
</dict>
<key>zapped_your_profile_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@ZAPPED@</string>
<key>ZAPPED</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%2$@ and %1$d other zapped your profile</string>
<key>other</key>
<string>%2$@ and %1$d others zapped your profile</string>
</dict>
</dict>
<key>zaps_count</key> <key>zaps_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d otra nota</string> <string>... %d otra nota ...</string>
<key>many</key>
<string>... %d otras notas ...</string>
<key>other</key> <key>other</key>
<string>%d otras notas</string> <string>... %d otras notas...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -28,11 +32,11 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Seguidor</string> <string>Seguidor</string>
<key>many</key>
<string>Seguidores</string>
<key>other</key> <key>other</key>
<string>Seguidores</string> <string>Seguidores</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -46,6 +50,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Reacción</string> <string>Reacción</string>
<key>many</key>
<string>Reacciones</string>
<key>other</key> <key>other</key>
<string>Reacciones</string> <string>Reacciones</string>
</dict> </dict>
@@ -62,6 +68,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Relé</string> <string>Relé</string>
<key>many</key>
<string>Relés</string>
<key>other</key> <key>other</key>
<string>Relés</string> <string>Relés</string>
</dict> </dict>
@@ -69,7 +77,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Respondiendo a %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +85,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> y %d otro</string> <string>Respondiendo a %2$@ y %1$d otro</string>
<key>many</key>
<string>Respondiendo a %2$@ y %1$d otros</string>
<key>other</key> <key>other</key>
<string> y %d otros</string> <string>Respondiendo a %2$@ y %1$d otros</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Respondiendo a %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +103,11 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> y %d otro</string> <string>Respondiendo a %2$@, %3$@ y %1$d otro</string>
<key>many</key>
<string>Respondiendo a %2$@, %3$@ y %1$d otros</string>
<key>other</key> <key>other</key>
<string> y %d otros</string> <string>Respondiendo a %2$@, %3$@ y %1$d otros</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
@@ -114,6 +122,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Republicación</string> <string>Republicación</string>
<key>many</key>
<string>Republicaciones</string>
<key>other</key> <key>other</key>
<string>Republicaciones</string> <string>Republicaciones</string>
</dict> </dict>
@@ -130,6 +140,8 @@
<string>@</string> <string>@</string>
<key>one</key> <key>one</key>
<string>%2$@ sat</string> <string>%2$@ sat</string>
<key>many</key>
<string>%2$@ sats</string>
<key>other</key> <key>other</key>
<string>%2$@ sats</string> <string>%2$@ sats</string>
</dict> </dict>
@@ -146,6 +158,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Zap</string> <string>Zap</string>
<key>many</key>
<string>Zaps</string>
<key>other</key> <key>other</key>
<string>Zaps</string> <string>Zaps</string>
</dict> </dict>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d autre note</string> <string>... %d autre note ...</string>
<key>many</key>
<string>... %d autres notes ...</string>
<key>other</key> <key>other</key>
<string>%d autres notes</string> <string>... %d autres notes ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -28,11 +32,11 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Abonné</string> <string>Abonné</string>
<key>many</key>
<string>Abonnés</string>
<key>other</key> <key>other</key>
<string>Abonnés</string> <string>Abonnés</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -46,6 +50,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Réaction</string> <string>Réaction</string>
<key>many</key>
<string>Réactions</string>
<key>other</key> <key>other</key>
<string>Réactions</string> <string>Réactions</string>
</dict> </dict>
@@ -62,6 +68,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Relais</string> <string>Relais</string>
<key>many</key>
<string>Relais</string>
<key>other</key> <key>other</key>
<string>Relais</string> <string>Relais</string>
</dict> </dict>
@@ -69,7 +77,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Réponse à %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +85,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d autre</string> <string>Réponse à %2$@ &amp; %1$d autre</string>
<key>many</key>
<string>Réponse à %2$@ &amp; %1$d autres</string>
<key>other</key> <key>other</key>
<string> &amp; %d autres</string> <string>Réponse à %2$@ &amp; %1$d autres</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Réponse à %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +103,11 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d autre</string> <string>Réponse à %2$@, %3$@ &amp; %1$d autre</string>
<key>many</key>
<string>Réponse à %2$@, %3$@ &amp; %1$d autres</string>
<key>other</key> <key>other</key>
<string> &amp; %d autres</string> <string>Réponse à %2$@, %3$@ &amp; %1$d autres</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
@@ -114,6 +122,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Republication</string> <string>Republication</string>
<key>many</key>
<string>Republications</string>
<key>other</key> <key>other</key>
<string>Republications</string> <string>Republications</string>
</dict> </dict>
@@ -130,6 +140,8 @@
<string>@</string> <string>@</string>
<key>one</key> <key>one</key>
<string>%2$@ sat</string> <string>%2$@ sat</string>
<key>many</key>
<string>%2$@ sats</string>
<key>other</key> <key>other</key>
<string>%2$@ sats</string> <string>%2$@ sats</string>
</dict> </dict>
@@ -146,6 +158,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Zap</string> <string>Zap</string>
<key>many</key>
<string>Zaps</string>
<key>other</key> <key>other</key>
<string>Zaps</string> <string>Zaps</string>
</dict> </dict>

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,13 +13,13 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string>%d Note Lainnya</string> <string>... %d Note Lainnya ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -27,8 +29,6 @@
<key>other</key> <key>other</key>
<string>Pengikut</string> <string>Pengikut</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -61,7 +61,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Membalas ke %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -69,15 +69,13 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string>&amp; %d lainnya</string> <string>Membalas ke %2$@ &amp; %1$d lainnya</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Membalas ke %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -85,9 +83,7 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string>&amp; %d lainnya</string> <string>Membalas ke %2$@, %3$@ &amp; %1$d lainnya</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d altra nota</string> <string>... %d altra nota ...</string>
<key>many</key>
<string>... %d altre note ...</string>
<key>other</key> <key>other</key>
<string>%d altre note</string> <string>... %d altre note ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -28,11 +32,11 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Seguace</string> <string>Seguace</string>
<key>many</key>
<string>Seguaci</string>
<key>other</key> <key>other</key>
<string>Seguaci</string> <string>Seguaci</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -46,6 +50,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Reazione</string> <string>Reazione</string>
<key>many</key>
<string>Reazioni</string>
<key>other</key> <key>other</key>
<string>Reazioni</string> <string>Reazioni</string>
</dict> </dict>
@@ -62,6 +68,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Relè</string> <string>Relè</string>
<key>many</key>
<string>Relè</string>
<key>other</key> <key>other</key>
<string>Relè</string> <string>Relè</string>
</dict> </dict>
@@ -69,7 +77,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Rispondendo a %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +85,17 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d altro</string> <string>Rispondendo a %2$@ &amp; %1$d altro</string>
<key>many</key>
<string>Rispondendo a %2$@ &amp; %1$d altri</string>
<key>other</key> <key>other</key>
<string> &amp; %d altri</string> <string>Rispondendo a %2$@ &amp; %1$d altri</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Rispondendo a %@, %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +103,11 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string> &amp; %d altro</string> <string>Rispondendo a %2$@, %3$@ &amp; %1$d altro</string>
<key>many</key>
<string>Rispondendo a %2$@, %3$@ &amp; %1$d altri</string>
<key>other</key> <key>other</key>
<string> &amp; %d altri</string> <string>Rispondendo a %2$@, %3$@ &amp; %1$d altri</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
@@ -114,6 +122,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Repost</string> <string>Repost</string>
<key>many</key>
<string>I Repost</string>
<key>other</key> <key>other</key>
<string>I Repost</string> <string>I Repost</string>
</dict> </dict>
@@ -130,6 +140,8 @@
<string>@</string> <string>@</string>
<key>one</key> <key>one</key>
<string>%2$@ sat</string> <string>%2$@ sat</string>
<key>many</key>
<string>%2$@ sats</string>
<key>other</key> <key>other</key>
<string>%2$@ sats</string> <string>%2$@ sats</string>
</dict> </dict>
@@ -146,6 +158,8 @@
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>Zap</string> <string>Zap</string>
<key>many</key>
<string>Zaps</string>
<key>other</key> <key>other</key>
<string>Zaps</string> <string>Zaps</string>
</dict> </dict>

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,13 +13,13 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string>%d その他のNote</string> <string>... %d その他のNote ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -27,8 +29,6 @@
<key>other</key> <key>other</key>
<string>フォロワー</string> <string>フォロワー</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -61,7 +61,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>%@%#@OTHERS@ にリプライ</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -69,15 +69,13 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string> &amp; %d その他</string> <string>%2$@ &amp; %1$d その他にリプライ</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>%@, %@%#@OTHERS@ にリプライ</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -85,9 +83,7 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>other</key> <key>other</key>
<string> &amp; %d その他</string> <string>%2$@, %3$@ &amp; %1$d その他 にリプライ</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>

View File

@@ -4,164 +4,164 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string>%d cita ziņa</string>
<key>other</key>
<string>%d citas ziņas</string>
<key>zero</key> <key>zero</key>
<string>%d other notes</string> <string>... %d other notes ...</string>
<key>one</key>
<string>... %d cita ziņa ...</string>
<key>other</key>
<string>... %d citas ziņas ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· Ziņas ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>Followers</string>
<key>one</key> <key>one</key>
<string>Sekotājs</string> <string>Sekotājs</string>
<key>other</key> <key>other</key>
<string>Sekotāji</string> <string>Sekotāji</string>
<key>zero</key>
<string>Followers</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>Sekotāji</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Reakcijas</string> <string>%#@REACTIONS@</string>
<key>REACTIONS</key> <key>REACTIONS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>Reactions</string>
<key>one</key> <key>one</key>
<string>Reakcija</string> <string>Reakcija</string>
<key>other</key> <key>other</key>
<string>Reakcijas</string> <string>Reakcijas</string>
<key>zero</key>
<string>Reactions</string>
</dict> </dict>
</dict> </dict>
<key>relays_count</key> <key>relays_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Releji</string> <string>%#@RELAYS@</string>
<key>RELAYS</key> <key>RELAYS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>Relays</string>
<key>one</key> <key>one</key>
<string>Relejs</string> <string>Relejs</string>
<key>other</key> <key>other</key>
<string>Releji</string> <string>Releji</string>
<key>zero</key>
<string>Relays</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Atbildot %@% #Citam</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string> &amp; %d cits</string>
<key>other</key>
<string> &amp; %d citiem</string>
<key>zero</key> <key>zero</key>
<string></string> <string>Atbildot %2$@ &amp; %1$d others</string>
<key>one</key>
<string>Atbildot %2$@ &amp; %1$d cits</string>
<key>other</key>
<string>Atbildot %2$@ &amp; %1$d citiem</string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Atbildot %@, %@%#Citiem</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key>
<string> &amp; %d cits</string>
<key>other</key>
<string> &amp; %d citiem</string>
<key>zero</key> <key>zero</key>
<string></string> <string>Atbildot %2$@, %3$@ &amp; %1$d others</string>
<key>one</key>
<string>Atbildot %2$@, %3$@ &amp; %1$d cits</string>
<key>other</key>
<string>Atbildot %2$@, %3$@ &amp; %1$d citiem</string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Pārpublicējumi</string> <string>%#@REPOSTS@</string>
<key>REPOSTS</key> <key>REPOSTS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>Reposts</string>
<key>one</key> <key>one</key>
<string>Pārpublicēt</string> <string>Pārpublicēt</string>
<key>other</key> <key>other</key>
<string>Pārpublicējumi</string> <string>Pārpublicējumi</string>
<key>zero</key>
<string>Reposts</string>
</dict> </dict>
</dict> </dict>
<key>sats_count</key> <key>sats_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>%1$#@Sats@</string> <string>%1$#@SATS@</string>
<key>SATS</key> <key>SATS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>@</string> <string>@</string>
<key>zero</key>
<string>%2$@ sats</string>
<key>one</key> <key>one</key>
<string>%2$@ sati</string> <string>%2$@ sati</string>
<key>other</key> <key>other</key>
<string>%2$@ sati</string> <string>%2$@ sati</string>
<key>zero</key>
<string>%2$@ sats</string>
</dict> </dict>
</dict> </dict>
<key>zaps_count</key> <key>zaps_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Zapi</string> <string>%#@ZAPS@</string>
<key>ZAPS</key> <key>ZAPS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string> <string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>zero</key>
<string>Zaps</string>
<key>one</key> <key>one</key>
<string>Zaps</string> <string>Zaps</string>
<key>other</key> <key>other</key>
<string>Zapi</string> <string>Zapi</string>
<key>zero</key>
<string>Zaps</string>
</dict> </dict>
</dict> </dict>
</dict> </dict>

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,8 @@
<dict> <dict>
<key>collapsed_event_view_other_notes</key> <key>collapsed_event_view_other_notes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@NOTES@</string>
<key>NOTES</key> <key>NOTES</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -11,15 +13,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>%d andere notitie</string> <string>... %d andere notitie ...</string>
<key>other</key> <key>other</key>
<string>%d andere notities</string> <string>... %d andere notities ...</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>··· %#@NOTES@ ···</string>
</dict> </dict>
<key>followers_count</key> <key>followers_count</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
<key>FOLLOWERS</key> <key>FOLLOWERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -31,8 +33,6 @@
<key>other</key> <key>other</key>
<string>Volgers</string> <string>Volgers</string>
</dict> </dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
</dict> </dict>
<key>reactions_count</key> <key>reactions_count</key>
<dict> <dict>
@@ -69,7 +69,7 @@
<key>replying_to_one_and_others</key> <key>replying_to_one_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Antwoord aan %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -77,17 +77,15 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>en %d andere gebruiker</string> <string>Antwoord aan %2$@ en %1$d andere gebruiker</string>
<key>other</key> <key>other</key>
<string>en %d andere gebruikers</string> <string>Antwoord aan %2$@ en %1$d andere gebruikers</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>replying_to_two_and_others</key> <key>replying_to_two_and_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
<string>Antwoord aan %@ en %@%#@OTHERS@</string> <string>%#@OTHERS@</string>
<key>OTHERS</key> <key>OTHERS</key>
<dict> <dict>
<key>NSStringFormatSpecTypeKey</key> <key>NSStringFormatSpecTypeKey</key>
@@ -95,11 +93,9 @@
<key>NSStringFormatValueTypeKey</key> <key>NSStringFormatValueTypeKey</key>
<string>d</string> <string>d</string>
<key>one</key> <key>one</key>
<string>en %d andere gebruiker</string> <string>Antwoord aan %2$@, %3$@ en %1$d andere gebruiker</string>
<key>other</key> <key>other</key>
<string>en %d andere gebruikers</string> <string>Antwoord aan %2$@, %3$@ en %1$d andere gebruikers</string>
<key>zero</key>
<string></string>
</dict> </dict>
</dict> </dict>
<key>reposts_count</key> <key>reposts_count</key>

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More