Skip to content

Commit

Permalink
Merge pull request #1717 from planetary-social/bdm/refactor-picker
Browse files Browse the repository at this point in the history
update to custom styled segmented picker
  • Loading branch information
bryanmontz authored Dec 31, 2024
2 parents c2fe8cd + 9f9d9a3 commit 8a5ed3e
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for decrypting private tags in kind 30000 lists.
- Added pop-up tip for feed customization. [#101](https://github.com/verse-pbc/issues/issues/101)
- Added remembering which feed source is selected.
- Factored out the segmented picker on the ProfileHeader for reusability.

### Internal Changes
- Upgraded to Xcode 16. [#1570](https://github.com/planetary-social/nos/issues/1570)
Expand Down
4 changes: 4 additions & 0 deletions Nos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@
501728B42D16EFB000CF2A07 /* FeedPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501728B32D16EFAC00CF2A07 /* FeedPicker.swift */; };
5022F9462D2186380012FF4B /* follow_set_private.json in Resources */ = {isa = PBXBuildFile; fileRef = 5022F9452D2186300012FF4B /* follow_set_private.json */; };
5022FB352D2303F30012FF4B /* FeedSelectorTip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5022FB342D2303F00012FF4B /* FeedSelectorTip.swift */; };
5022FBCF2D242C850012FF4B /* NosSegmentedPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5022FBCE2D242C810012FF4B /* NosSegmentedPicker.swift */; };
502B6C3D2C9462A400446316 /* PushNotificationRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502B6C3C2C9462A400446316 /* PushNotificationRegistrar.swift */; };
503CA9532D19ACCC00805EF8 /* HorizontalLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503CA9522D19ACC800805EF8 /* HorizontalLine.swift */; };
503CA9792D19C39F00805EF8 /* FeedCustomizerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503CA9782D19C39800805EF8 /* FeedCustomizerView.swift */; };
Expand Down Expand Up @@ -768,6 +769,7 @@
5022F9452D2186300012FF4B /* follow_set_private.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = follow_set_private.json; sourceTree = "<group>"; };
5022F9472D2188650012FF4B /* Nos 23.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Nos 23.xcdatamodel"; sourceTree = "<group>"; };
5022FB342D2303F00012FF4B /* FeedSelectorTip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedSelectorTip.swift; sourceTree = "<group>"; };
5022FBCE2D242C810012FF4B /* NosSegmentedPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NosSegmentedPicker.swift; sourceTree = "<group>"; };
502B6C3C2C9462A400446316 /* PushNotificationRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationRegistrar.swift; sourceTree = "<group>"; };
503CA9522D19ACC800805EF8 /* HorizontalLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalLine.swift; sourceTree = "<group>"; };
503CA9782D19C39800805EF8 /* FeedCustomizerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCustomizerView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1625,6 +1627,7 @@
2D4010A12AD87DF300F93AD4 /* KnownFollowersView.swift */,
C9A0DADC29C689C900466635 /* NosNavigationBar.swift */,
C97B28892C10B07100DC1FC0 /* NosNavigationStack.swift */,
5022FBCE2D242C810012FF4B /* NosSegmentedPicker.swift */,
042406F22C907A15008F2A21 /* NosToggle.swift */,
C9B708BA2A13BE41006C613A /* NoteTextEditor.swift */,
C986510F2B0BD49200597B68 /* PagedNoteListView.swift */,
Expand Down Expand Up @@ -2414,6 +2417,7 @@
C9CE5B142A0172CF008E198C /* WebView.swift in Sources */,
CD4908D429B92941007443DB /* ReportABugMailView.swift in Sources */,
0314D5AC2C7D31060002E7F4 /* MediaService.swift in Sources */,
5022FBCF2D242C850012FF4B /* NosSegmentedPicker.swift in Sources */,
5B7C93B02B6AD52400410ABE /* CreateUsernameWizard.swift in Sources */,
030036852C5D39DD002C71F5 /* RefreshController.swift in Sources */,
C9C2B78229E0735400548B4A /* RelaySubscriptionManager.swift in Sources */,
Expand Down
41 changes: 41 additions & 0 deletions Nos/Views/Components/NosSegmentedPicker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import SwiftUI

protocol NosSegmentedPickerItem: Equatable, Identifiable {
var titleKey: LocalizedStringKey { get }
var image: Image { get }
}

/// A custom styled segmented picker.
///
/// Pass in an array of items that conform to ``NosSegmentedPickerItem`` as
/// well as a binding to a selected item of the same type.
struct NosSegmentedPicker<Item: NosSegmentedPickerItem>: View {

let items: [Item]
@Binding var selectedItem: Item

var body: some View {
HStack {
ForEach(items) { item in
Button {
selectedItem = item
} label: {
HStack {
Spacer()
let color = selectedItem == item ? Color.primaryTxt : .secondaryTxt
item.image
.renderingMode(.template)
.foregroundColor(color)
Text(item.titleKey)
.font(.subheadline.weight(.medium))
.foregroundColor(color)
Spacer()
}
}
.frame(maxWidth: .infinity)
}
}
.padding(.top, 12)
.padding(.bottom, 15)
}
}
44 changes: 35 additions & 9 deletions Nos/Views/Home/FeedCustomizerView.swift
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
import SwiftUI

enum FeedTab: String {
case lists
case relays
}

extension FeedTab: NosSegmentedPickerItem {
var id: String {
rawValue
}

var titleKey: LocalizedStringKey {
switch self {
case .lists:
"Lists"
case .relays:
"Relays"
}
}

var image: Image {
switch self {
case .lists:
Image(systemName: "person.2")
case .relays:
Image(systemName: "dot.radiowaves.left.and.right")
}
}
}

struct FeedCustomizerView: View {

@Environment(FeedController.self) var feedController
let author: Author
@Binding var shouldNavigateToRelays: Bool

@AppStorage("selectedFeedTogglesTab") private var selectedTab = "Lists"
@AppStorage("selectedFeedTogglesTab") private var selectedTab = FeedTab.lists

var body: some View {
VStack(spacing: 0) {
BeveledContainerView {
Picker("", selection: $selectedTab) {
Text("Lists").tag("Lists")
Text("Relays").tag("Relays")
}
.pickerStyle(.segmented)
.padding(.vertical, 10)
.padding(.horizontal, 16)
NosSegmentedPicker(
items: [FeedTab.lists, FeedTab.relays],
selectedItem: $selectedTab
)
}

if selectedTab == "Lists" {
if selectedTab == .lists {
FeedSourceToggleView(
author: author,
headerText: Text("Add lists to your feed to filter by topic."),
Expand Down
30 changes: 30 additions & 0 deletions Nos/Views/Profile/ProfileFeedType.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CoreData
import SwiftUI

/// An enumeration of the different feed algorithms the user can choose to view on the Profile screen.
enum ProfileFeedType {
Expand All @@ -21,3 +22,32 @@ enum ProfileFeedType {
return Filter(authorKeys: [author.hexadecimalPublicKey ?? "error"], kinds: kinds)
}
}

extension ProfileFeedType: NosSegmentedPickerItem {
var id: String {
switch self {
case .activity:
"activity"
case .notes:
"notes"
}
}

var titleKey: LocalizedStringKey {
switch self {
case .activity:
"activity"
case .notes:
"notes"
}
}

var image: Image {
switch self {
case .activity:
Image.profileFeed
case .notes:
Image.profilePosts
}
}
}
49 changes: 6 additions & 43 deletions Nos/Views/Profile/ProfileHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct ProfileHeader: View {
y: 1
)
}

var body: some View {
ZStack {
VStack(alignment: .leading) {
Expand Down Expand Up @@ -204,8 +204,11 @@ struct ProfileHeader: View {
.frame(maxWidth: .infinity)

divider

profileHeaderTab

NosSegmentedPicker(
items: [ProfileFeedType.notes, ProfileFeedType.activity],
selectedItem: $selectedTab
)
}
.frame(maxWidth: 500)
}
Expand Down Expand Up @@ -235,46 +238,6 @@ struct ProfileHeader: View {
.presentationDetents([.medium, .large])
}
}

private var profileHeaderTab: some View {
HStack {
Button {
selectedTab = .notes
} label: {
HStack {
Spacer()
let color = selectedTab == .notes ? Color.primaryTxt : .secondaryTxt
Image.profilePosts
.renderingMode(.template)
.foregroundColor(color)
Text("notes")
.font(.subheadline.weight(.medium))
.foregroundColor(color)
Spacer()
}
}
.frame(maxWidth: .infinity)

Button {
selectedTab = .activity
} label: {
HStack {
Spacer()
let color = selectedTab == .activity ? Color.primaryTxt : .secondaryTxt
Image.profileFeed
.renderingMode(.template)
.foregroundColor(color)
Text("activity")
.foregroundColor(color)
.font(.subheadline.weight(.medium))
Spacer()
}
}
.frame(maxWidth: .infinity)
}
.padding(.top, 12)
.padding(.bottom, 15)
}
}

#Preview {
Expand Down

0 comments on commit 8a5ed3e

Please sign in to comment.