Huge refactor to add better structure to the project. Separating features with their associated view and model structure. This should be better organization and will allow us to improve the overall architecture in the future. I forsee many more improvements that can follow this change. e.g. MVVM Arch As well as cleaning up duplicate, unused, functionality. Many files have global functions that can also be moved or be renamed. damus/ ├── Features/ │ ├── <Feature>/ │ │ ├── Views/ │ │ └── Models/ ├── Shared/ │ ├── Components/ │ ├── Media/ │ ├── Buttons/ │ ├── Extensions/ │ ├── Empty Views/ │ ├── ErrorHandling/ │ ├── Modifiers/ │ └── Utilities/ ├── Core/ │ ├── Nostr/ │ ├── NIPs/ │ ├── DIPs/ │ ├── Types/ │ ├── Networking/ │ └── Storage/ Signed-off-by: ericholguin <ericholguin@apache.org>
326 lines
9.2 KiB
Swift
326 lines
9.2 KiB
Swift
//
|
|
// Nostr.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2022-04-07.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
typealias Profile = NdbProfile
|
|
typealias ProfileKey = UInt64
|
|
//typealias ProfileRecord = NdbProfileRecord
|
|
|
|
class ProfileRecord {
|
|
let data: NdbProfileRecord
|
|
|
|
init(data: NdbProfileRecord, key: ProfileKey) {
|
|
self.data = data
|
|
self.profileKey = key
|
|
}
|
|
|
|
let profileKey: ProfileKey
|
|
var profile: Profile? { return data.profile }
|
|
var receivedAt: UInt64 { data.receivedAt }
|
|
var noteKey: UInt64 { data.noteKey }
|
|
|
|
private var _lnurl: String? = nil
|
|
var lnurl: String? {
|
|
if let _lnurl {
|
|
return _lnurl
|
|
}
|
|
|
|
guard let profile = data.profile,
|
|
let addr = (profile.lud16 ?? profile.lud06)?.trimmingCharacters(in: .whitespaces)
|
|
else {
|
|
return nil;
|
|
}
|
|
|
|
if addr.contains("@") {
|
|
// this is a heavy op and is used a lot in views, cache it!
|
|
let addr = lnaddress_to_lnurl(addr);
|
|
self._lnurl = addr
|
|
return addr
|
|
}
|
|
|
|
if !addr.lowercased().hasPrefix("lnurl") {
|
|
return nil
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
}
|
|
|
|
extension NdbProfile {
|
|
var display_name: String? {
|
|
return displayName
|
|
}
|
|
|
|
static func displayName(profile: Profile?, pubkey: Pubkey) -> DisplayName {
|
|
return DisplayName(name: profile?.name, display_name: profile?.display_name, pubkey: pubkey)
|
|
}
|
|
|
|
var damus_donation: Int? {
|
|
return Int(damusDonation)
|
|
}
|
|
|
|
var damus_donation_v2: Int {
|
|
return Int(damusDonationV2)
|
|
}
|
|
|
|
var website_url: URL? {
|
|
if self.website?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
|
|
return nil
|
|
}
|
|
return self.website.flatMap { url in
|
|
let trim = url.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if !(trim.hasPrefix("http://") || trim.hasPrefix("https://")) {
|
|
return URL(string: "https://" + trim)
|
|
}
|
|
return URL(string: trim)
|
|
}
|
|
}
|
|
|
|
init(name: String? = nil, display_name: String? = nil, about: String? = nil, picture: String? = nil, banner: String? = nil, website: String? = nil, lud06: String? = nil, lud16: String? = nil, nip05: String? = nil, damus_donation: Int? = nil, reactions: Bool = true) {
|
|
|
|
var fbb = FlatBufferBuilder()
|
|
|
|
let name_off = fbb.create(string: name)
|
|
let display_name_off = fbb.create(string: display_name)
|
|
let about_off = fbb.create(string: about)
|
|
let picture_off = fbb.create(string: picture)
|
|
let banner_off = fbb.create(string: banner)
|
|
let website_off = fbb.create(string: website)
|
|
let lud06_off = fbb.create(string: lud06)
|
|
let lud16_off = fbb.create(string: lud16)
|
|
let nip05_off = fbb.create(string: nip05)
|
|
|
|
let profile_data = NdbProfile.createNdbProfile(&fbb,
|
|
nameOffset: name_off,
|
|
websiteOffset: website_off,
|
|
aboutOffset: about_off,
|
|
lud16Offset: lud16_off,
|
|
bannerOffset: banner_off,
|
|
displayNameOffset: display_name_off,
|
|
reactions: reactions,
|
|
pictureOffset: picture_off,
|
|
nip05Offset: nip05_off,
|
|
damusDonation: 0,
|
|
damusDonationV2: damus_donation.map({ Int32($0) }) ?? 0,
|
|
lud06Offset: lud06_off)
|
|
|
|
fbb.finish(offset: profile_data)
|
|
|
|
var buf = ByteBuffer(bytes: fbb.sizedByteArray)
|
|
let profile: Profile = try! getCheckedRoot(byteBuffer: &buf)
|
|
self = profile
|
|
}
|
|
}
|
|
|
|
/*
|
|
class Profile: Codable {
|
|
var value: [String: AnyCodable]
|
|
|
|
init(name: String? = nil, display_name: String? = nil, about: String? = nil, picture: String? = nil, banner: String? = nil, website: String? = nil, lud06: String? = nil, lud16: String? = nil, nip05: String? = nil, damus_donation: Int? = nil) {
|
|
self.value = [:]
|
|
self.name = name
|
|
self.display_name = display_name
|
|
self.about = about
|
|
self.picture = picture
|
|
self.banner = banner
|
|
self.website = website
|
|
self.lud06 = lud06
|
|
self.lud16 = lud16
|
|
self.nip05 = nip05
|
|
self.damus_donation = damus_donation
|
|
}
|
|
|
|
private func str(_ str: String) -> String? {
|
|
return get_val(str)
|
|
}
|
|
|
|
private func int(_ key: String) -> Int? {
|
|
return get_val(key)
|
|
}
|
|
|
|
private func get_val<T>(_ v: String) -> T? {
|
|
guard let val = self.value[v] else{
|
|
return nil
|
|
}
|
|
|
|
guard let s = val.value as? T else {
|
|
return nil
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
private func set_val<T>(_ key: String, _ val: T?) {
|
|
if val == nil {
|
|
self.value.removeValue(forKey: key)
|
|
return
|
|
}
|
|
|
|
self.value[key] = AnyCodable.init(val)
|
|
}
|
|
|
|
private func set_str(_ key: String, _ val: String?) {
|
|
set_val(key, val)
|
|
}
|
|
|
|
private func set_int(_ key: String, _ val: Int?) {
|
|
set_val(key, val)
|
|
}
|
|
|
|
var reactions: Bool? {
|
|
get { return get_val("reactions"); }
|
|
set(s) { set_val("reactions", s) }
|
|
}
|
|
|
|
var display_name: String? {
|
|
get { return str("display_name"); }
|
|
set(s) { set_str("display_name", s) }
|
|
}
|
|
|
|
var name: String? {
|
|
get { return str("name"); }
|
|
set(s) { set_str("name", s) }
|
|
}
|
|
|
|
var about: String? {
|
|
get { return str("about"); }
|
|
set(s) { set_str("about", s) }
|
|
}
|
|
|
|
var damus_donation: Int? {
|
|
get { return int("damus_donation_v2"); }
|
|
set(s) { set_int("damus_donation_v2", s) }
|
|
}
|
|
|
|
var picture: String? {
|
|
get { return str("picture"); }
|
|
set(s) { set_str("picture", s) }
|
|
}
|
|
|
|
var banner: String? {
|
|
get { return str("banner"); }
|
|
set(s) { set_str("banner", s) }
|
|
}
|
|
|
|
var website: String? {
|
|
get { return str("website"); }
|
|
set(s) { set_str("website", s) }
|
|
}
|
|
|
|
var lud06: String? {
|
|
get { return str("lud06"); }
|
|
set(s) { set_str("lud06", s) }
|
|
}
|
|
|
|
var lud16: String? {
|
|
get { return str("lud16"); }
|
|
set(s) { set_str("lud16", s) }
|
|
}
|
|
|
|
var website_url: URL? {
|
|
if self.website?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
|
|
return nil
|
|
}
|
|
return self.website.flatMap { url in
|
|
let trim = url.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if !(trim.hasPrefix("http://") || trim.hasPrefix("https://")) {
|
|
return URL(string: "https://" + trim)
|
|
}
|
|
return URL(string: trim)
|
|
}
|
|
}
|
|
|
|
func cache_lnurl() {
|
|
guard self._lnurl == nil else {
|
|
return
|
|
}
|
|
|
|
guard let addr = lud16 ?? lud06 else {
|
|
return
|
|
}
|
|
|
|
self._lnurl = lnaddress_to_lnurl(addr)
|
|
}
|
|
|
|
private var _lnurl: String? = nil
|
|
var lnurl: String? {
|
|
if let _lnurl {
|
|
return _lnurl
|
|
}
|
|
|
|
guard let addr = lud16 ?? lud06 else {
|
|
return nil;
|
|
}
|
|
|
|
if addr.contains("@") {
|
|
// this is a heavy op and is used a lot in views, cache it!
|
|
let addr = lnaddress_to_lnurl(addr);
|
|
self._lnurl = addr
|
|
return addr
|
|
}
|
|
|
|
if !addr.lowercased().hasPrefix("lnurl") {
|
|
return nil
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
var nip05: String? {
|
|
get { return str("nip05"); }
|
|
set(s) { set_str("nip05", s) }
|
|
}
|
|
|
|
var lightning_uri: URL? {
|
|
return make_ln_url(self.lnurl)
|
|
}
|
|
|
|
init() {
|
|
self.value = [:]
|
|
}
|
|
|
|
required init(from decoder: Decoder) throws {
|
|
let container = try decoder.singleValueContainer()
|
|
self.value = try container.decode([String: AnyCodable].self)
|
|
}
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
var container = encoder.singleValueContainer()
|
|
try container.encode(value)
|
|
}
|
|
|
|
static func displayName(profile: Profile?, pubkey: Pubkey) -> DisplayName {
|
|
return parse_display_name(profile: profile, pubkey: pubkey)
|
|
}
|
|
}
|
|
*/
|
|
|
|
func make_test_profile() -> Profile {
|
|
return Profile(name: "jb55", display_name: "Will", about: "Its a me", picture: "https://cdn.jb55.com/img/red-me.jpg", banner: "https://pbs.twimg.com/profile_banners/9918032/1531711830/600x200", website: "jb55.com", lud06: nil, lud16: "jb55@jb55.com", nip05: "jb55@jb55.com", damus_donation: 1)
|
|
}
|
|
|
|
func make_ln_url(_ str: String?) -> URL? {
|
|
return str.flatMap { URL(string: "lightning:" + $0) }
|
|
}
|
|
|
|
func lnaddress_to_lnurl(_ lnaddr: String) -> String? {
|
|
let parts = lnaddr.split(separator: "@")
|
|
guard parts.count == 2 else {
|
|
return nil
|
|
}
|
|
|
|
let url = "https://\(parts[1])/.well-known/lnurlp/\(parts[0])";
|
|
guard let dat = url.data(using: .utf8) else {
|
|
return nil
|
|
}
|
|
|
|
return bech32_encode(hrp: "lnurl", Array(dat))
|
|
}
|
|
|