iOS client for Grain grain.social
ios photography atproto
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: edit profile opens as sheet with close button and prominent save

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+21 -4
+12 -4
Grain/Views/Profile/ProfileView.swift
··· 32 32 let actor: String 33 33 var isRoot = false 34 34 @State private var showCopiedToast = false 35 + @State private var showEditProfile = false 35 36 36 37 /// Resolved DID from the loaded profile, or the original actor identifier 37 38 private var did: String { ··· 247 248 .padding(.horizontal) 248 249 } else { 249 250 HStack(spacing: 8) { 250 - NavigationLink { 251 - EditProfileView(client: client, onSaved: { 252 - Task { await viewModel.load(did: did) } 253 - }) 251 + Button { 252 + showEditProfile = true 254 253 } label: { 255 254 Text("Edit Profile") 256 255 .font(.subheadline.weight(.semibold)) ··· 456 455 StoryCreateView(client: client, onCreated: { 457 456 Task { await viewModel.load(did: did) } 458 457 }) 458 + .environment(auth) 459 + } 460 + .sheet(isPresented: $showEditProfile) { 461 + NavigationStack { 462 + EditProfileView(client: client, onSaved: { 463 + showEditProfile = false 464 + Task { await viewModel.load(did: did) } 465 + }) 466 + } 459 467 .environment(auth) 460 468 } 461 469 .background(Color(.systemBackground))
+9
Grain/Views/Settings/EditProfileView.swift
··· 119 119 .navigationTitle("Edit Profile") 120 120 .navigationBarTitleDisplayMode(.inline) 121 121 .toolbar { 122 + ToolbarItem(placement: .topBarLeading) { 123 + Button { 124 + dismiss() 125 + } label: { 126 + Image(systemName: "xmark") 127 + } 128 + .tint(.primary) 129 + } 122 130 ToolbarItem(placement: .topBarTrailing) { 123 131 Button { 124 132 Task { await save() } ··· 130 138 .fontWeight(.semibold) 131 139 } 132 140 } 141 + .buttonStyle(.glassProminent) 133 142 .disabled(isSaving || displayName.count > maxDisplayName || bio.count > maxBio) 134 143 } 135 144 }