Merge commit 'f0d242a'
This commit is contained in:
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
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 */; };
|
||||||
|
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
|
||||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
||||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
||||||
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
|
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
|
||||||
@@ -148,6 +150,8 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
|
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
|
||||||
|
3169CAEC294FCCFC00EE4006 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = damus/Util/Constants.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
31D2E846295218AF006D67F8 /* Shimmer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmer.swift; sourceTree = "<group>"; };
|
||||||
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
|
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
|
||||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
|
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
|
||||||
4C06670828FDE64700038D2A /* damus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "damus-Bridging-Header.h"; sourceTree = "<group>"; };
|
4C06670828FDE64700038D2A /* damus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "damus-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
@@ -504,6 +508,7 @@
|
|||||||
4C285C8B28398BC6008A31F1 /* Keys.swift */,
|
4C285C8B28398BC6008A31F1 /* Keys.swift */,
|
||||||
4C90BD19283AA67F008EE7EF /* Bech32.swift */,
|
4C90BD19283AA67F008EE7EF /* Bech32.swift */,
|
||||||
4C216F352870A9A700040376 /* InputDismissKeyboard.swift */,
|
4C216F352870A9A700040376 /* InputDismissKeyboard.swift */,
|
||||||
|
3169CAEC294FCCFC00EE4006 /* Constants.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -511,6 +516,7 @@
|
|||||||
4CE4F9DF285287A000C00DD9 /* Components */ = {
|
4CE4F9DF285287A000C00DD9 /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
31D2E846295218AF006D67F8 /* Shimmer.swift */,
|
||||||
4CE4F9E0285287B800C00DD9 /* TextFieldAlert.swift */,
|
4CE4F9E0285287B800C00DD9 /* TextFieldAlert.swift */,
|
||||||
4CD7641A28A1641400B6928F /* EndBlock.swift */,
|
4CD7641A28A1641400B6928F /* EndBlock.swift */,
|
||||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */,
|
4C06670528FCB08600038D2A /* ImageCarousel.swift */,
|
||||||
@@ -695,6 +701,7 @@
|
|||||||
4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */,
|
4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */,
|
||||||
4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */,
|
4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */,
|
||||||
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||||
|
3169CAE9294FCABA00EE4006 /* XCRemoteSwiftPackageReference "Shimmer" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@@ -781,6 +788,7 @@
|
|||||||
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
||||||
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
|
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
|
||||||
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */,
|
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */,
|
||||||
|
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */,
|
||||||
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */,
|
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */,
|
||||||
4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */,
|
4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */,
|
||||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */,
|
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */,
|
||||||
@@ -846,6 +854,7 @@
|
|||||||
4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */,
|
4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */,
|
||||||
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
|
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
|
||||||
4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */,
|
4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */,
|
||||||
|
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -1197,6 +1206,14 @@
|
|||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
3169CAE9294FCABA00EE4006 /* XCRemoteSwiftPackageReference "Shimmer" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/joshuajhomann/Shimmer";
|
||||||
|
requirement = {
|
||||||
|
branch = master;
|
||||||
|
kind = branch;
|
||||||
|
};
|
||||||
|
};
|
||||||
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
||||||
|
|||||||
@@ -17,6 +17,15 @@
|
|||||||
"revision" : "40b4b38b3b1c83f7088c76189a742870e0ca06a9"
|
"revision" : "40b4b38b3b1c83f7088c76189a742870e0ca06a9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "shimmer",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/joshuajhomann/Shimmer",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "2fde687b3f1d9c5409c53da095d3686361e41343"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "starscream",
|
"identity" : "starscream",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
77
damus/Components/Shimmer.swift
Normal file
77
damus/Components/Shimmer.swift
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// Shimmer.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Joshua Homann on 2/20/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
public struct ShimmerConfiguration {
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
public let gradient: Gradient
|
||||||
|
public let initialLocation: (start: UnitPoint, end: UnitPoint)
|
||||||
|
public let finalLocation: (start: UnitPoint, end: UnitPoint)
|
||||||
|
public let duration: TimeInterval
|
||||||
|
public let opacity: Double
|
||||||
|
public static let `default` = ShimmerConfiguration(
|
||||||
|
gradient: Gradient(stops: [
|
||||||
|
.init(color: .clear, location: 0),
|
||||||
|
.init(color: .black, location: 0.3),
|
||||||
|
.init(color: .black, location: 0.7),
|
||||||
|
.init(color: .clear, location: 1),
|
||||||
|
]),
|
||||||
|
initialLocation: (start: UnitPoint(x: -1, y: 0.5), end: .leading),
|
||||||
|
finalLocation: (start: .trailing, end: UnitPoint(x: 2, y: 0.5)),
|
||||||
|
duration: 2,
|
||||||
|
opacity: 0.6
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ShimmeringView<Content: View>: View {
|
||||||
|
private let content: () -> Content
|
||||||
|
private let configuration: ShimmerConfiguration
|
||||||
|
@State private var startPoint: UnitPoint
|
||||||
|
@State private var endPoint: UnitPoint
|
||||||
|
init(configuration: ShimmerConfiguration, @ViewBuilder content: @escaping () -> Content) {
|
||||||
|
self.configuration = configuration
|
||||||
|
self.content = content
|
||||||
|
_startPoint = .init(wrappedValue: configuration.initialLocation.start)
|
||||||
|
_endPoint = .init(wrappedValue: configuration.initialLocation.end)
|
||||||
|
}
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
content()
|
||||||
|
LinearGradient(
|
||||||
|
gradient: configuration.gradient,
|
||||||
|
startPoint: startPoint,
|
||||||
|
endPoint: endPoint
|
||||||
|
)
|
||||||
|
.opacity(configuration.opacity)
|
||||||
|
.blendMode(.overlay)
|
||||||
|
.onAppear {
|
||||||
|
withAnimation(Animation.linear(duration: configuration.duration).repeatForever(autoreverses: false)) {
|
||||||
|
startPoint = configuration.finalLocation.start
|
||||||
|
endPoint = configuration.finalLocation.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ShimmerModifier: ViewModifier {
|
||||||
|
let configuration: ShimmerConfiguration
|
||||||
|
public func body(content: Content) -> some View {
|
||||||
|
ShimmeringView(configuration: configuration) { content }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public extension View {
|
||||||
|
func shimmer(configuration: ShimmerConfiguration = .default) -> some View {
|
||||||
|
modifier(ShimmerModifier(configuration: configuration))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -549,3 +549,4 @@ func setup_notifications() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
damus/Util/Constants.swift
Normal file
25
damus/Util/Constants.swift
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Constants.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Sam DuBois on 12/18/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
static let PUB_KEY = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||||
|
|
||||||
|
static let EXAMPLE_DEMOS = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: PUB_KEY, privkey: "privkey"), likes: EventCounter(our_pubkey: PUB_KEY), boosts: EventCounter(our_pubkey: PUB_KEY), contacts: Contacts(), tips: TipCounter(our_pubkey: PUB_KEY), profiles: Profiles(), dms: DirectMessagesModel())
|
||||||
|
|
||||||
|
static let EXAMPLE_EVENTS = [
|
||||||
|
NostrEvent(content: "Icecream", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "This is a test for a really long note that somebody sent because they thought they were super cool or maybe they were just really excited to share something with the world.", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "Bonjour Le Monde", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "Why am I helping on this app? Because it's fun!", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "PIzza", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "Hello World! This is so cool!", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
NostrEvent(content: "Nostr - Damus... Haha get it?", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ struct EventActionBar: View {
|
|||||||
|
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||||
.font(.footnote)
|
.font(.footnote.weight(.medium))
|
||||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||||
|
|
||||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||||
@@ -58,7 +58,7 @@ struct EventActionBar: View {
|
|||||||
|
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||||
.font(.footnote)
|
.font(.footnote.weight(.medium))
|
||||||
.foregroundColor(bar.liked ? Color.red : Color.gray)
|
.foregroundColor(bar.liked ? Color.red : Color.gray)
|
||||||
|
|
||||||
EventActionButton(img: bar.liked ? "heart.fill" : "heart", col: bar.liked ? Color.red : nil) {
|
EventActionButton(img: bar.liked ? "heart.fill" : "heart", col: bar.liked ? Color.red : nil) {
|
||||||
@@ -140,7 +140,7 @@ struct EventActionBar: View {
|
|||||||
func EventActionButton(img: String, col: Color?, action: @escaping () -> ()) -> some View {
|
func EventActionButton(img: String, col: Color?, action: @escaping () -> ()) -> some View {
|
||||||
Button(action: action) {
|
Button(action: action) {
|
||||||
Label("", systemImage: img)
|
Label("", systemImage: img)
|
||||||
.font(.footnote)
|
.font(.footnote.weight(.medium))
|
||||||
.foregroundColor(col == nil ? Color.gray : col!)
|
.foregroundColor(col == nil ? Color.gray : col!)
|
||||||
}
|
}
|
||||||
.padding(.trailing, 40)
|
.padding(.trailing, 40)
|
||||||
|
|||||||
@@ -83,17 +83,22 @@ struct EventView: View {
|
|||||||
|
|
||||||
NavigationLink(destination: booster_profile) {
|
NavigationLink(destination: booster_profile) {
|
||||||
HStack {
|
HStack {
|
||||||
Label("", systemImage: "arrow.2.squarepath")
|
Image(systemName: "arrow.2.squarepath")
|
||||||
|
.font(.footnote.weight(.bold))
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
ProfileName(pubkey: event.pubkey, profile: damus.profiles.lookup(id: event.pubkey), contacts: damus.contacts, show_friend_confirmed: show_friend_icon)
|
if let prof = damus.profiles.lookup(id: event.pubkey) {
|
||||||
.foregroundColor(Color.gray)
|
Text(Profile.displayName(profile: prof, pubkey: event.pubkey))
|
||||||
Text(" Boosted")
|
.font(.footnote.weight(.bold))
|
||||||
|
.foregroundColor(Color.gray)
|
||||||
|
}
|
||||||
|
Text("Boosted")
|
||||||
|
.font(.footnote.weight(.bold))
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
TextEvent(inner_ev, pubkey: inner_ev.pubkey)
|
TextEvent(inner_ev, pubkey: inner_ev.pubkey)
|
||||||
.padding([.top], 2)
|
.padding([.top], 1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TextEvent(event, pubkey: pubkey)
|
TextEvent(event, pubkey: pubkey)
|
||||||
@@ -119,11 +124,12 @@ struct EventView: View {
|
|||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
ProfileName(pubkey: pubkey, profile: profile, contacts: damus.contacts, show_friend_confirmed: show_friend_icon)
|
EventProfileName(pubkey: pubkey, profile: profile, contacts: damus.contacts, show_friend_confirmed: show_friend_icon)
|
||||||
Text("\(format_relative_time(event.created_at))")
|
Text("\(format_relative_time(event.created_at))")
|
||||||
|
.font(.body)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.is_reply(damus.keypair.privkey) {
|
if event.is_reply(damus.keypair.privkey) {
|
||||||
Text("\(reply_desc(profiles: damus.profiles, event: event))")
|
Text("\(reply_desc(profiles: damus.profiles, event: event))")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct FollowButtonView: View {
|
struct FollowButtonView: View {
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
let target: FollowTarget
|
let target: FollowTarget
|
||||||
@State var follow_state: FollowState
|
@State var follow_state: FollowState
|
||||||
|
|
||||||
@@ -16,15 +19,15 @@ struct FollowButtonView: View {
|
|||||||
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))
|
Text(follow_btn_txt(follow_state))
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 25)
|
||||||
.padding(.vertical, 7)
|
.padding(.vertical, 10)
|
||||||
.font(.caption.weight(.bold))
|
.font(.caption.weight(.bold))
|
||||||
.foregroundColor(follow_state == .unfollows ? .white : .black)
|
.foregroundColor(follow_state == .unfollows ? emptyColor() : fillColor())
|
||||||
.background(follow_state == .unfollows ? .black : .white)
|
.background(follow_state == .unfollows ? fillColor() : emptyColor())
|
||||||
.cornerRadius(20)
|
.cornerRadius(20)
|
||||||
.overlay {
|
.overlay {
|
||||||
RoundedRectangle(cornerRadius: 16)
|
RoundedRectangle(cornerRadius: 16)
|
||||||
.stroke(follow_state == .unfollows ? .white : .gray, lineWidth: 1)
|
.stroke(follow_state == .unfollows ? .clear : borderColor(), lineWidth: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.followed)) { notif in
|
.onReceive(handle_notify(.followed)) { notif in
|
||||||
@@ -44,6 +47,18 @@ struct FollowButtonView: View {
|
|||||||
self.follow_state = .unfollows
|
self.follow_state = .unfollows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fillColor() -> Color {
|
||||||
|
colorScheme == .light ? .black : .white
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyColor() -> Color {
|
||||||
|
colorScheme == .light ? .white : .black
|
||||||
|
}
|
||||||
|
|
||||||
|
func borderColor() -> Color {
|
||||||
|
colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FollowButtonPreviews: View {
|
struct FollowButtonPreviews: View {
|
||||||
|
|||||||
@@ -64,8 +64,10 @@ struct NoteContentView: View {
|
|||||||
return VStack(alignment: .leading) {
|
return VStack(alignment: .leading) {
|
||||||
if let txt = try? AttributedString(markdown: artifacts.content, options: md_opts) {
|
if let txt = try? AttributedString(markdown: artifacts.content, options: md_opts) {
|
||||||
Text(txt)
|
Text(txt)
|
||||||
|
.font(.body)
|
||||||
} else {
|
} else {
|
||||||
Text(artifacts.content)
|
Text(artifacts.content)
|
||||||
|
.font(.body)
|
||||||
}
|
}
|
||||||
if show_images && artifacts.images.count > 0 {
|
if show_images && artifacts.images.count > 0 {
|
||||||
ImageCarousel(urls: artifacts.images)
|
ImageCarousel(urls: artifacts.images)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct ProfileFullName: View {
|
|||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
} else {
|
} else {
|
||||||
ProfileName(pubkey: pubkey, profile: profile, contacts: contacts, show_friend_confirmed: true)
|
// ProfileName(pubkey: pubkey, profile: profile, contacts: contacts, show_friend_confirmed: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,8 +73,9 @@ struct ProfileName: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
|
|
||||||
Text(prefix + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
|
Text(prefix + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
|
||||||
//.foregroundColor(hex_to_rgb(pubkey))
|
.font(.body)
|
||||||
.fontWeight(prefix == "@" ? .none : .bold)
|
.fontWeight(prefix == "@" ? .none : .bold)
|
||||||
if let frend = friend_icon {
|
if let frend = friend_icon {
|
||||||
Label("", systemImage: frend)
|
Label("", systemImage: frend)
|
||||||
@@ -92,4 +93,76 @@ struct ProfileName: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Profile Name used when displaying an event in the timeline
|
||||||
|
struct EventProfileName: View {
|
||||||
|
let pubkey: String
|
||||||
|
let profile: Profile?
|
||||||
|
let contacts: Contacts
|
||||||
|
let prefix: String
|
||||||
|
|
||||||
|
let show_friend_confirmed: Bool
|
||||||
|
|
||||||
|
@State var display_name: String?
|
||||||
|
|
||||||
|
init(pubkey: String, profile: Profile?, contacts: Contacts, show_friend_confirmed: Bool) {
|
||||||
|
self.pubkey = pubkey
|
||||||
|
self.profile = profile
|
||||||
|
self.prefix = ""
|
||||||
|
self.contacts = contacts
|
||||||
|
self.show_friend_confirmed = show_friend_confirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
init(pubkey: String, profile: Profile?, prefix: String, contacts: Contacts, show_friend_confirmed: Bool) {
|
||||||
|
self.pubkey = pubkey
|
||||||
|
self.profile = profile
|
||||||
|
self.prefix = prefix
|
||||||
|
self.contacts = contacts
|
||||||
|
self.show_friend_confirmed = show_friend_confirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
var friend_icon: String? {
|
||||||
|
if !show_friend_confirmed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.contacts.is_friend(self.pubkey) {
|
||||||
|
return "person.fill.checkmark"
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.contacts.is_friend_of_friend(self.pubkey) {
|
||||||
|
return "person.fill.and.arrow.left.and.arrow.right"
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
if let real_name = profile?.display_name {
|
||||||
|
Text(real_name)
|
||||||
|
.font(.body.weight(.bold))
|
||||||
|
|
||||||
|
Text("@" + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.font(.body)
|
||||||
|
} else {
|
||||||
|
Text(String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
|
||||||
|
.font(.body)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let frend = friend_icon {
|
||||||
|
Label("", systemImage: frend)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.font(.footnote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||||
|
let update = notif.object as! ProfileUpdate
|
||||||
|
if update.pubkey != pubkey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
display_name = Profile.displayName(profile: update.profile, pubkey: pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ struct ProfileView: View {
|
|||||||
}) {
|
}) {
|
||||||
Image(systemName: "bolt.circle")
|
Image(systemName: "bolt.circle")
|
||||||
.symbolRenderingMode(.palette)
|
.symbolRenderingMode(.palette)
|
||||||
.foregroundStyle(colorScheme == .dark ? .white : .black, .gray)
|
.font(.system(size: 34).weight(.thin))
|
||||||
.font(.system(size: 27).weight(.thin))
|
.foregroundStyle(colorScheme == .light ? .black : .white, colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,8 +107,8 @@ struct ProfileView: View {
|
|||||||
return NavigationLink(destination: dmview) {
|
return NavigationLink(destination: dmview) {
|
||||||
Image(systemName: "bubble.left.circle")
|
Image(systemName: "bubble.left.circle")
|
||||||
.symbolRenderingMode(.palette)
|
.symbolRenderingMode(.palette)
|
||||||
.font(.system(size: 29).weight(.thin))
|
.font(.system(size: 34).weight(.thin))
|
||||||
.foregroundStyle(colorScheme == .dark ? .white : .black, .gray)
|
.foregroundStyle(colorScheme == .light ? .black : .white, colorScheme == .light ? .black.opacity(0.1) : .white.opacity(0.2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +134,7 @@ struct ProfileView: View {
|
|||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
|
|
||||||
Text(data?.about ?? "")
|
Text(data?.about ?? "")
|
||||||
|
.font(.subheadline)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
@@ -144,7 +145,9 @@ struct ProfileView: View {
|
|||||||
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("\(profile.following)")
|
Text("\(profile.following)")
|
||||||
|
.font(.subheadline.weight(.medium))
|
||||||
Text("Following")
|
Text("Following")
|
||||||
|
.font(.subheadline)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +158,9 @@ struct ProfileView: View {
|
|||||||
NavigationLink(destination: fview) {
|
NavigationLink(destination: fview) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("\(followers.contacts.count)")
|
Text("\(followers.contacts.count)")
|
||||||
|
.font(.subheadline.weight(.medium))
|
||||||
Text("Followers")
|
Text("Followers")
|
||||||
|
.font(.subheadline)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,19 @@ struct SearchHomeView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var GlobalContent: some View {
|
var GlobalContent: some View {
|
||||||
TimelineView(events: $model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: { _ in true })
|
return TimelineView(events: $model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: { _ in true })
|
||||||
|
.refreshable {
|
||||||
|
// Fetch new information by resubscribing to the relay
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var SearchContent: some View {
|
var SearchContent: some View {
|
||||||
SearchResultsView(damus_state: damus_state, search: $search)
|
SearchResultsView(damus_state: damus_state, search: $search)
|
||||||
|
.refreshable {
|
||||||
|
// Fetch new information by resubscribing to the relay
|
||||||
|
model.subscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
|
|||||||
@@ -40,7 +40,27 @@ struct InnerTimelineView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InnerTimelineRedactedView: View {
|
||||||
|
let events: [NostrEvent]
|
||||||
|
let damus: DamusState
|
||||||
|
let show_friend_icon: Bool
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
ForEach(events, id: \.id) { event in
|
||||||
|
EventView(event: event, highlight: .none, has_action_bar: true, damus: damus, show_friend_icon: show_friend_icon)
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shimmer()
|
||||||
|
.redacted(reason: .placeholder)
|
||||||
|
.padding(.horizontal)
|
||||||
|
.disabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct TimelineView: View {
|
struct TimelineView: View {
|
||||||
|
|
||||||
@Binding var events: [NostrEvent]
|
@Binding var events: [NostrEvent]
|
||||||
@Binding var loading: Bool
|
@Binding var loading: Bool
|
||||||
|
|
||||||
@@ -56,6 +76,7 @@ struct TimelineView: View {
|
|||||||
ScrollViewReader { scroller in
|
ScrollViewReader { scroller in
|
||||||
ScrollView {
|
ScrollView {
|
||||||
if loading {
|
if loading {
|
||||||
|
InnerTimelineRedactedView(events: Constants.EXAMPLE_EVENTS, damus: damus, show_friend_icon: true)
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.progressViewStyle(.circular)
|
.progressViewStyle(.circular)
|
||||||
} else {
|
} else {
|
||||||
@@ -72,13 +93,11 @@ struct TimelineView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct TimelineView_Previews: PreviewProvider {
|
struct TimelineView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
TimelineView()
|
TimelineView(events: .constant(Constants.EXAMPLE_EVENTS), loading: .constant(true), damus: Constants.EXAMPLE_DEMOS, show_friend_icon: true, filter: { _ in true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
struct NavigationLazyView<Content: View>: View {
|
struct NavigationLazyView<Content: View>: View {
|
||||||
@@ -90,4 +109,3 @@ struct NavigationLazyView<Content: View>: View {
|
|||||||
build()
|
build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user