Merge branch 'master' into local-relay-model

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
Daniel D’Aquino
2025-10-29 16:43:00 -07:00
13 changed files with 377 additions and 7 deletions

View File

@@ -4,6 +4,32 @@ _[Please provide a summary of the changes in this PR.]_
## Checklist
<!--
CHOOSE YOUR CHECKLIST:
- If this is an EXPERIMENTAL DAMUS LABS FEATURE, follow the "Experimental Feature Checklist" below and DELETE the "Standard PR Checklist"
- If this is a STANDARD PR, follow the "Standard PR Checklist" below and DELETE the "Experimental Feature Checklist"
-->
### Experimental Feature Checklist
<!-- DELETE THIS SECTION if this is a standard PR -->
> [!TIP]
> This Pull Request is an experimental feature for Damus Labs, and follows a fast-track review process.
> The overall requirements are lowered and the review process is not as strict as usual. However, the feature will only be available for Purple users who opt-in.
- [ ] I have read (or I am familiar with) the [Contribution Guidelines](../docs/CONTRIBUTING.md).
- [ ] I have done some testing on the changes in this PR to ensure it is at least functional.
- [ ] I made sure that this new feature is only available when the user opts-in from the Damus Labs screen, and does not affect the rest of the app when turned off.
- [ ] My PR is either small, or I have split it into smaller logical commits that are easier to review.
- [ ] I have added the signoff line to all my commits. See [Signing off your work](../docs/CONTRIBUTING.md#sign-your-work---the-developers-certificate-of-origin).
- [ ] I have added an appropriate changelog entry to my commit in this PR. See [Adding changelog entries](../docs/CONTRIBUTING.md#add-changelog-changed-changelog-fixed-etc).
- Example changelog entry: `Changelog-Added: Added experimental feature <X> to Damus Labs`
### Standard PR Checklist
<!-- DELETE THIS SECTION if this is an experimental Damus Labs feature -->
- [ ] I have read (or I am familiar with) the [Contribution Guidelines](../docs/CONTRIBUTING.md)
- [ ] I have tested the changes in this PR
- [ ] I have profiled the changes to ensure there are no performance regressions, or I do not need to profile the changes.

View File

@@ -543,6 +543,18 @@
5CB017312D4422DB00A9ED05 /* NWCSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017302D4422D600A9ED05 /* NWCSettings.swift */; };
5CB017322D4422DB00A9ED05 /* NWCSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017302D4422D600A9ED05 /* NWCSettings.swift */; };
5CB017332D4422DB00A9ED05 /* NWCSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB017302D4422D600A9ED05 /* NWCSettings.swift */; };
5CB645982EA317D20018BD91 /* DamusLabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645972EA317CC0018BD91 /* DamusLabs.swift */; };
5CB645992EA317D20018BD91 /* DamusLabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645972EA317CC0018BD91 /* DamusLabs.swift */; };
5CB6459A2EA317D20018BD91 /* DamusLabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645972EA317CC0018BD91 /* DamusLabs.swift */; };
5CB6459C2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */; };
5CB6459D2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */; };
5CB6459E2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */; };
5CB645A12EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
5CB645A22EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
5CB645A32EA31E410018BD91 /* LabsLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */; };
5CB645A92EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
5CB645AA2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
5CB645AB2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */; };
5CC8529D2BD741CD0039FFC5 /* HighlightEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */; };
5CC8529F2BD744F60039FFC5 /* HighlightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC8529E2BD744F60039FFC5 /* HighlightView.swift */; };
5CC852A22BDED9B90039FFC5 /* HighlightDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */; };
@@ -2566,6 +2578,10 @@
5CB017242D42C5BD00A9ED05 /* TransactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsView.swift; sourceTree = "<group>"; };
5CB0172C2D42C76600A9ED05 /* BalanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceView.swift; sourceTree = "<group>"; };
5CB017302D4422D600A9ED05 /* NWCSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWCSettings.swift; sourceTree = "<group>"; };
5CB645972EA317CC0018BD91 /* DamusLabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabs.swift; sourceTree = "<group>"; };
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsIntroduction.swift; sourceTree = "<group>"; };
5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabsLogoView.swift; sourceTree = "<group>"; };
5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLabsExpirements.swift; sourceTree = "<group>"; };
5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightEvent.swift; sourceTree = "<group>"; };
5CC8529E2BD744F60039FFC5 /* HighlightView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightView.swift; sourceTree = "<group>"; };
5CC852A12BDED9B90039FFC5 /* HighlightDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightDescription.swift; sourceTree = "<group>"; };
@@ -4045,6 +4061,7 @@
5C78A7872E30345900CF177D /* Longform */,
5C78A7842E30340E00CF177D /* FollowPack */,
4CFF8F5729C9FD07008DB934 /* Purple */,
5CB645962EA3106A0018BD91 /* Labs */,
4CE879562996C44A00F758CC /* Zaps */,
4C7D095A2A098C5C00943473 /* Wallet */,
4CCEB7AC29B53D180078AA28 /* Search */,
@@ -4867,6 +4884,33 @@
path = Views;
sourceTree = "<group>";
};
5CB645952EA3106A0018BD91 /* Views */ = {
isa = PBXGroup;
children = (
5CB645A82EAC013A0018BD91 /* DamusLabsExpirements.swift */,
5CB6459B2EA31D750018BD91 /* LabsIntroduction.swift */,
5CB645972EA317CC0018BD91 /* DamusLabs.swift */,
);
path = Views;
sourceTree = "<group>";
};
5CB645962EA3106A0018BD91 /* Labs */ = {
isa = PBXGroup;
children = (
5CB6459F2EA31E2C0018BD91 /* Detail */,
5CB645952EA3106A0018BD91 /* Views */,
);
path = Labs;
sourceTree = "<group>";
};
5CB6459F2EA31E2C0018BD91 /* Detail */ = {
isa = PBXGroup;
children = (
5CB645A02EA31E3D0018BD91 /* LabsLogoView.swift */,
);
path = Detail;
sourceTree = "<group>";
};
7C0F392D29B57C8F0039859C /* Extensions */ = {
isa = PBXGroup;
children = (
@@ -5538,6 +5582,7 @@
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */,
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
2710433D2E6BFE340005C3B0 /* PostingTimelineSwitcherView.swift in Sources */,
5CB6459A2EA317D20018BD91 /* DamusLabs.swift in Sources */,
4CEE2AF5280B29E600AB5EEF /* TimeAgo.swift in Sources */,
4CC14FF12A73FCDB007AEB17 /* Pubkey.swift in Sources */,
5C8711DE2C460C06007879C2 /* PostingTimelineView.swift in Sources */,
@@ -5919,6 +5964,7 @@
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
D5C1AFD42E5EE2820092F72F /* FavoriteButtonView.swift in Sources */,
5CB645AB2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
D5C1AFCA2E5EE12B0092F72F /* ContactCardNotify.swift in Sources */,
4CA352A82A76B37E003BB08B /* NewMutesNotify.swift in Sources */,
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
@@ -5976,6 +6022,7 @@
4C73C5142A4437C10062CAC0 /* ZapUserView.swift in Sources */,
501F8C802A0220E1001AFC1D /* KeychainStorage.swift in Sources */,
3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */,
5CB645A22EA31E410018BD91 /* LabsLogoView.swift in Sources */,
4C1A9A1D29DDCF9B00516EAC /* NotificationSettingsView.swift in Sources */,
5CC868DD2AA29B3200FB22BA /* NeutralButtonStyle.swift in Sources */,
4C75EFB528049D790006080F /* Relay.swift in Sources */,
@@ -5998,6 +6045,7 @@
D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */,
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
D733F9E82D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
5CB6459C2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */,
D77135D42E7B766B00E7639F /* DataExtensions.swift in Sources */,
D74EA0902D2E271E002290DD /* ErrorView.swift in Sources */,
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
@@ -6084,6 +6132,7 @@
5C4FA7FB2DC29C3800CE658C /* FollowPackView.swift in Sources */,
4C3624722D5EA18E00DD066E /* amount.c in Sources */,
4C3624712D5EA18300DD066E /* error.c in Sources */,
5CB645A92EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
4C3624702D5EA17700DD066E /* utf8.c in Sources */,
4C36246F2D5EA16A00DD066E /* str.c in Sources */,
4C36246E2D5EA10400DD066E /* hash_u5.c in Sources */,
@@ -6237,6 +6286,7 @@
82D6FB2C2CD99F7900C925F4 /* ImageMetadata.swift in Sources */,
D71527FF2E0A3D6900C893D6 /* InterestList.swift in Sources */,
82D6FB2D2CD99F7900C925F4 /* ImageProcessing.swift in Sources */,
5CB6459D2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */,
82D6FB2E2CD99F7900C925F4 /* BlurHashEncode.swift in Sources */,
82D6FB2F2CD99F7900C925F4 /* BlurHashDecode.swift in Sources */,
82D6FB302CD99F7900C925F4 /* PostBox.swift in Sources */,
@@ -6474,6 +6524,7 @@
82D6FC092CD99F7900C925F4 /* AboutView.swift in Sources */,
D72C01332E78C10500AACB67 /* CondensedProfilePicturesViewModel.swift in Sources */,
82D6FC0A2CD99F7900C925F4 /* ProfileName.swift in Sources */,
5CB645982EA317D20018BD91 /* DamusLabs.swift in Sources */,
82D6FC0B2CD99F7900C925F4 /* ProfilePictureSelector.swift in Sources */,
82D6FC0C2CD99F7900C925F4 /* EditMetadataView.swift in Sources */,
82D6FC0D2CD99F7900C925F4 /* EditPictureControl.swift in Sources */,
@@ -6486,6 +6537,7 @@
82D6FC122CD99F7900C925F4 /* EventProfileName.swift in Sources */,
82D6FC132CD99F7900C925F4 /* FriendIcon.swift in Sources */,
82D6FC142CD99F7900C925F4 /* CondensedProfilePicturesView.swift in Sources */,
5CB645A32EA31E410018BD91 /* LabsLogoView.swift in Sources */,
82D6FC152CD99F7900C925F4 /* ProfileEditButton.swift in Sources */,
D73BDB102D6FF5F600D69970 /* NostrNetworkManager.swift in Sources */,
82D6FC162CD99F7900C925F4 /* RelayPaidDetail.swift in Sources */,
@@ -6739,6 +6791,7 @@
D73E5E872C6A97F4007EB227 /* DamusPurple.swift in Sources */,
D73E5F992C6AA864007EB227 /* InvoicesView.swift in Sources */,
D73E5E882C6A97F4007EB227 /* StoreObserver.swift in Sources */,
5CB645992EA317D20018BD91 /* DamusLabs.swift in Sources */,
D73E5E892C6A97F4007EB227 /* DamusPurpleURL.swift in Sources */,
D73E5E8A2C6A97F4007EB227 /* PurpleStoreKitManager.swift in Sources */,
D733F9E72D92C76100317B11 /* UnownedNdbNote.swift in Sources */,
@@ -6903,6 +6956,7 @@
D73E5F0E2C6A97F4007EB227 /* FriendIcon.swift in Sources */,
D73E5F0F2C6A97F4007EB227 /* CondensedProfilePicturesView.swift in Sources */,
D73E5F102C6A97F4007EB227 /* ProfileEditButton.swift in Sources */,
5CB6459E2EA31D8E0018BD91 /* LabsIntroduction.swift in Sources */,
D73E5F112C6A97F4007EB227 /* RelayPaidDetail.swift in Sources */,
D7AACFFF2E0387B800FB7699 /* LnurlAmountView.swift in Sources */,
D73E5F122C6A97F4007EB227 /* RelayAuthenticationDetail.swift in Sources */,
@@ -7053,6 +7107,7 @@
D703D7A52C670E3E00A400EA /* mdb.c in Sources */,
D703D76B2C670B3100A400EA /* Referenced.swift in Sources */,
D73BDB192D71311900D69970 /* UserRelayListErrors.swift in Sources */,
5CB645A12EA31E410018BD91 /* LabsLogoView.swift in Sources */,
D703D7582C670A6000A400EA /* Id.swift in Sources */,
5C05675A2C8FBDE70073F23A /* NDBSearchView.swift in Sources */,
D703D76E2C670B4900A400EA /* NdbTagsIterator.swift in Sources */,
@@ -7097,6 +7152,7 @@
D73E5E162C6A9619007EB227 /* PostView.swift in Sources */,
D703D7872C670C7E00A400EA /* DamusPurpleEnvironment.swift in Sources */,
D703D7892C670C8600A400EA /* DeepLPlan.swift in Sources */,
5CB645AA2EAC01430018BD91 /* DamusLabsExpirements.swift in Sources */,
D73E5E182C6A963D007EB227 /* AttachMediaUtility.swift in Sources */,
D73E5F852C6AA628007EB227 /* LoadScript.swift in Sources */,
D703D74E2C6709DA00A400EA /* Pubkey.swift in Sources */,

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "damooseLabs.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View File

@@ -196,6 +196,9 @@ struct ContentView: View {
}
}
}
.onAppear {
notify(.display_tabbar(true))
}
}
func MaybeReportView(target: ReportTarget) -> some View {
@@ -305,8 +308,10 @@ struct ContentView: View {
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: .mixWithOthers)
setup_notifications()
if !hasSeenOnboardingSuggestions || damus_state!.settings.always_show_onboarding_suggestions {
active_sheet = .onboardingSuggestions
hasSeenOnboardingSuggestions = true
if damus_state.is_privkey_user {
active_sheet = .onboardingSuggestions
hasSeenOnboardingSuggestions = true
}
}
self.appDelegate?.state = damus_state
Task { // We probably don't need this to be a detached task. According to https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/#Defining-and-Calling-Asynchronous-Functions, awaits are only suspension points that do not block the thread.

View File

@@ -0,0 +1,62 @@
//
// LabsLogoView.swift
// damus
//
// Created by eric on 10/17/25.
//
import SwiftUI
struct LabsLogoView: View {
var body: some View {
HStack(spacing: 20) {
Image("damus-dark-logo")
.resizable()
.frame(width: 60, height: 60)
.clipShape(RoundedRectangle(cornerRadius: 15.0))
.overlay(
RoundedRectangle(cornerRadius: 15)
.stroke(LinearGradient(
colors: [DamusColors.lighterPink.opacity(0.8), .white.opacity(0), DamusColors.deepPurple.opacity(0.6)],
startPoint: .topLeading,
endPoint: .bottomTrailing), lineWidth: 1)
)
.shadow(radius: 5)
VStack(alignment: .leading) {
HStack(spacing: 0) {
Text("Labs ", comment: "Feature name")
.font(.system(size: 60.0).weight(.bold))
.foregroundColor(.white)
.tracking(-2)
Image(systemName: "flask.fill")
.padding(.top, 25)
.foregroundStyle(
LinearGradient(
colors: [DamusColors.deepPurple, DamusColors.lighterPink],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
Image(systemName: "testtube.2")
.padding(.top, 25)
.foregroundStyle(
LinearGradient(
colors: [DamusColors.lighterPink, DamusColors.deepPurple],
startPoint: .bottomLeading,
endPoint: .topTrailing
)
)
}
}
}
.padding(.bottom, 30)
}
}
#Preview {
PurpleBackdrop {
LabsLogoView()
}
}

View File

@@ -0,0 +1,71 @@
//
// DamusLabs.swift
// damus
//
// Created by eric on 10/17/25.
//
import SwiftUI
import StoreKit
struct DamusLabsView: View {
let damus_state: DamusState
@State var purple_account: DamusPurple.Account?
@State var show_intro_sheet: Bool = true
@State private var shouldDismissView = false
@Environment(\.dismiss) var dismiss
init(damus_state: DamusState) {
self.damus_state = damus_state
self.purple_account = nil
}
var body: some View {
NavigationView {
PurpleBackdrop {
VStack {
MainContent
.padding(.top, 125)
}
}
.navigationBarHidden(true)
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: BackNav())
}
.onReceive(handle_notify(.switched_timeline)) { _ in
dismiss()
}
.onAppear {
notify(.display_tabbar(false))
}
.task {
if damus_state.purple.enable_purple {
self.purple_account = try? await damus_state.purple.get_maybe_cached_account(pubkey: damus_state.pubkey)
}
}
.ignoresSafeArea(.all)
}
var MainContent: some View {
VStack {
LabsLogoView()
if let purple_account, purple_account.active == true {
DamusLabsExpirements(damus_state: damus_state)
} else {
LabsIntroductionView(damus_state: damus_state)
}
Spacer()
}
}
}
struct DamusLabsView_Previews: PreviewProvider {
static var previews: some View {
DamusLabsView(damus_state: test_damus_state)
}
}

View File

@@ -0,0 +1,52 @@
//
// DamusLabsExpirements.swift
// damus
//
// Created by eric on 10/24/25.
//
import SwiftUI
struct DamusLabsExpirements: View {
let damus_state: DamusState
var body: some View {
VStack {
VStack(alignment: .leading, spacing: 30) {
PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("As a subscriber, youre getting an early look at new and innovative tools. These are beta features — still being tested and tuned. Try them out, share your thoughts, and help us perfect whats next.", comment: "Damus Labs explainer"))
.multilineTextAlignment(.center)
HStack {
Spacer()
Text("Features coming soon!")
.font(.title2)
.foregroundColor(.white)
.fontWeight(.bold)
.padding(.bottom, 2)
Spacer()
}
.padding(15)
.background(DamusColors.neutral6)
.cornerRadius(15)
.padding(.top, 10)
}
.padding([.trailing, .leading], 30)
.padding(.bottom, 20)
Image("damooseLabs")
.resizable()
.aspectRatio(contentMode: .fill)
}
}
}
#Preview {
PurpleBackdrop {
DamusLabsExpirements(damus_state: test_damus_state)
}
}

View File

@@ -0,0 +1,53 @@
//
// LabsIntroduction.swift
// damus
//
// Created by eric on 10/17/25.
//
import SwiftUI
struct LabsIntroductionView: View {
let damus_state: DamusState
var body: some View {
VStack {
VStack(alignment: .leading, spacing: 30) {
PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Purple subscribers get first access to new and experimental features — fresh ideas straight from the lab.", comment: "Damus purple subscription pitch"))
.multilineTextAlignment(.center)
HStack {
NavigationLink(destination: DamusPurpleView(damus_state: damus_state)) {
HStack(spacing: 10) {
Spacer()
Text("Learn more about Purple")
.foregroundColor(Color.white)
Spacer()
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background {
RoundedRectangle(cornerRadius: 12)
.fill(PinkGradient)
}
}
}
}
.padding([.trailing, .leading], 30)
.padding(.bottom, 20)
Image("damooseLabs")
.resizable()
.aspectRatio(contentMode: .fill)
}
}
}
#Preview {
PurpleBackdrop {
LabsIntroductionView(damus_state: test_damus_state)
}
}

View File

@@ -68,9 +68,6 @@ struct DamusPurpleView: View, DamusPurpleStoreKitManagerDelegate {
self.account_uuid = try await damus_state.purple.get_maybe_cached_uuid_for_account()
}
}
.onDisappear {
notify(.display_tabbar(true))
}
.onReceive(handle_notify(.purple_account_update), perform: { account in
self.my_account_info_state = .loaded(account: account)
})

View File

@@ -58,6 +58,22 @@ struct SideMenuView: View {
}
}
NavigationLink(destination: DamusLabsView(damus_state: damus_state)) {
HStack(spacing: 23) {
Image(systemName: "flask")
.fontWeight(.bold)
.tint(DamusColors.adaptableBlack)
Text("Labs")
.font(.title2.weight(.semibold))
.foregroundColor(DamusColors.adaptableBlack)
.frame(maxWidth: .infinity, alignment: .leading)
.dynamicTypeSize(.xSmall)
.minimumScaleFactor(0.5)
.lineLimit(1)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
NavigationLink(value: Route.MuteList) {
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
}

View File

@@ -50,6 +50,15 @@ struct TimelineView<Content: View>: View {
MainContent
}
var topPadding: CGFloat {
if #available(iOS 26.0, *) {
headerHeight
}
else {
headerHeight - getSafeAreaTop()
}
}
var MainContent: some View {
ScrollViewReader { scroller in
ScrollView {
@@ -65,7 +74,7 @@ struct TimelineView<Content: View>: View {
.redacted(reason: loading ? .placeholder : [])
.shimmer(loading)
.disabled(loading)
.padding(.top, headerHeight - getSafeAreaTop())
.padding(.top, topPadding)
.offsetY { previous, current in
if previous > current{
if direction != .up && current < 0 {

View File

@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDesignRequiresCompatibility</key>
<true/>
<key>NSUserActivityTypes</key>
<array>
<string>INSendMessageIntent</string>