Skip to content

Commit 809432d

Browse files
authored
Merge pull request #922 from DimensionDev/ios/20250508
add x spaces list
2 parents 023976d + 5f2e25f commit 809432d

File tree

2 files changed

+168
-22
lines changed

2 files changed

+168
-22
lines changed

iosApp/iosApp/Localizable.xcstrings

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16832,6 +16832,7 @@
1683216832
}
1683316833
},
1683416834
"Confirm" : {
16835+
"extractionState" : "stale",
1683516836
"localizations" : {
1683616837
"ar" : {
1683716838
"stringUnit" : {
@@ -24103,6 +24104,7 @@
2410324104
}
2410424105
},
2410524106
"Enter Podcast/Space ID" : {
24107+
"extractionState" : "stale",
2410624108
"localizations" : {
2410724109
"ar" : {
2410824110
"stringUnit" : {
@@ -24598,6 +24600,9 @@
2459824600
}
2459924601
}
2460024602
}
24603+
},
24604+
"Error Loading Spaces" : {
24605+
2460124606
},
2460224607
"fans_title" : {
2460324608
"comment" : "",
@@ -29615,6 +29620,9 @@
2961529620
},
2961629621
"Instance Rules" : {
2961729622

29623+
},
29624+
"Invalid item at index \\(index)" : {
29625+
2961829626
},
2961929627
"like" : {
2962029628
"comment" : "",
@@ -32341,6 +32349,9 @@
3234132349
}
3234232350
}
3234332351
}
32352+
},
32353+
"Live" : {
32354+
3234432355
},
3234532356
"LIVE" : {
3234632357
"localizations" : {
@@ -32955,6 +32966,9 @@
3295532966
}
3295632967
}
3295732968
}
32969+
},
32970+
"Loading Spaces..." : {
32971+
3295832972
},
3295932973
"local_filter_add" : {
3296032974
"comment" : "",
@@ -73366,6 +73380,9 @@
7336673380
}
7336773381
}
7336873382
}
73383+
},
73384+
"No Spaces Available" : {
73385+
7336973386
},
7337073387
"no_accounts" : {
7337173388
"localizations" : {
@@ -85422,6 +85439,7 @@
8542285439
}
8542385440
},
8542485441
"Set Test Replay ID" : {
85442+
"extractionState" : "stale",
8542585443
"localizations" : {
8542685444
"ar" : {
8542785445
"stringUnit" : {
@@ -102717,6 +102735,9 @@
102717102735
}
102718102736
}
102719102737
}
102738+
},
102739+
"There are currently no live or recorded Spaces to show." : {
102740+
102720102741
},
102721102742
"This might be because the current user is not set, the instance host is not configured, or data is still loading." : {
102722102743

@@ -107831,6 +107852,7 @@
107831107852
}
107832107853
},
107833107854
"XSpace Test" : {
107855+
"extractionState" : "stale",
107834107856
"localizations" : {
107835107857
"ar" : {
107836107858
"stringUnit" : {
@@ -107955,6 +107977,7 @@
107955107977
}
107956107978
},
107957107979
"XSpaces list comming soon" : {
107980+
"extractionState" : "stale",
107958107981
"localizations" : {
107959107982
"ar" : {
107960107983
"stringUnit" : {
@@ -108077,6 +108100,9 @@
108077108100
}
108078108101
}
108079108102
}
108103+
},
108104+
"You follow the X Spaces" : {
108105+
108080108106
},
108081108107
"Your account doesn't have any feeds" : {
108082108108
"localizations" : {
Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,161 @@
11
import shared
22
import SwiftUI
3+
import Kingfisher
34

45
struct SpaceScreen: View {
56
let accountType: AccountType
67
@EnvironmentObject private var router: FlareRouter
7-
@State private var podcastIdInput: String = ""
8+
@State private var presenter: PodcastListPresenter
9+
10+
init(accountType: AccountType) {
11+
self.accountType = accountType
12+
_presenter = .init(initialValue: PodcastListPresenter(accountType: accountType))
13+
}
814

915
var body: some View {
10-
VStack(spacing: 20) {
11-
Text("XSpaces list comming soon")
16+
ObservePresenter(presenter: presenter) { state in
17+
feedsListView(state)
18+
}
19+
}
20+
21+
@ViewBuilder
22+
private func feedsListView(_ state: PodcastListPresenterState) -> some View {
23+
switch onEnum(of: state.data) {
24+
case .loading:
25+
loadingView
26+
case let .success(successData):
27+
if successData.data.count == 0 {
28+
emptyView()
29+
} else {
30+
podcastsListView(podcastsList: successData.data)
31+
}
32+
case let .error(errorState):
33+
errorView(errorState: errorState)
34+
}
35+
}
36+
37+
private var loadingView: some View {
38+
VStack {
39+
ProgressView("Loading Spaces...")
40+
Spacer()
41+
}
42+
.frame(maxWidth: .infinity, maxHeight: .infinity)
43+
}
44+
45+
@ViewBuilder
46+
private func podcastsListView(podcastsList: NSArray) -> some View {
47+
List {
48+
ForEach(0 ..< podcastsList.count, id: \.self) { index in
49+
if let podcast = podcastsList[index] as? UiPodcast {
50+
PodcastRowView(podcast: podcast, accountType: accountType)
51+
} else {
52+
Text("Invalid item at index \\(index)")
53+
.foregroundColor(.red)
54+
}
55+
}
56+
}
57+
.listStyle(.plain)
58+
.navigationTitle("You follow the X Spaces")
59+
.navigationBarTitleDisplayMode(.inline)
60+
}
61+
62+
private func emptyView() -> some View {
63+
VStack(spacing: 16) {
64+
Image(systemName: "mic.slash.fill")
65+
.font(.largeTitle)
66+
.foregroundColor(.secondary)
67+
Text("No Spaces Available")
68+
.font(.headline)
69+
Text("There are currently no live or recorded Spaces to show.")
70+
.font(.subheadline)
71+
.foregroundColor(.gray)
72+
}
73+
.frame(maxWidth: .infinity, maxHeight: .infinity)
74+
}
75+
76+
private func errorView(errorState: UiStateError<NSArray>) -> some View {
77+
let errorMessage = errorState.throwable.message ?? "An unknown error occurred"
78+
return VStack(spacing: 16) {
79+
Image(systemName: "exclamationmark.triangle.fill")
1280
.font(.largeTitle)
13-
.padding(.top)
81+
.foregroundColor(.red)
82+
Text("Error Loading Spaces")
83+
.font(.headline)
84+
Text(errorMessage)
85+
.font(.subheadline)
86+
.foregroundColor(.gray)
87+
.multilineTextAlignment(.center)
88+
.padding(.horizontal)
89+
.buttonStyle(.borderedProminent)
90+
}
91+
.frame(maxWidth: .infinity, maxHeight: .infinity)
92+
}
93+
}
94+
95+
private struct PodcastRowView: View {
96+
let podcast: UiPodcast
97+
let accountType: AccountType
98+
@EnvironmentObject private var router: FlareRouter
1499

100+
var body: some View {
101+
VStack(alignment: .leading, spacing: 8) {
15102
HStack {
16-
TextField("Enter Podcast/Space ID", text: $podcastIdInput)
17-
.textFieldStyle(.roundedBorder)
18-
.autocapitalization(.none)
19-
.disableAutocorrection(true)
20-
21-
Button("Confirm") {
22-
guard !podcastIdInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return }
23-
router.navigate(to: .podcastSheet(accountType: accountType, podcastId: podcastIdInput))
103+
if !podcast.ended {
104+
LiveIndicatorView()
24105
}
25-
.buttonStyle(.borderedProminent)
26-
.disabled(podcastIdInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
106+
Spacer()
107+
// Image(systemName: "ellipsis")
108+
// .foregroundColor(.secondary)
27109
}
28-
.padding(.horizontal)
29110

30-
Button("Set Test Replay ID") {
31-
podcastIdInput = "1jMJgkygVkXJL"
111+
Text(podcast.title)
112+
.font(.title3.weight(.semibold))
113+
.lineLimit(3)
114+
115+
// HStack(spacing: 4) {
116+
// Image(systemName: "headphones")
117+
// Text("\(podcast.listeners.count) Listening")
118+
// }
119+
// .font(.subheadline)
120+
// .foregroundColor(.secondary)
121+
// .padding(.bottom, 4)
122+
123+
HStack(spacing: 8) {
124+
KFImage(URL(string: podcast.creator.avatar))
125+
.resizable()
126+
.placeholder { Image(systemName: "person.circle.fill").resizable().foregroundColor(.gray) }
127+
.aspectRatio(contentMode: .fill)
128+
.frame(width: 24, height: 24)
129+
.clipShape(Circle())
130+
131+
Text(podcast.creator.name.raw)
132+
.font(.subheadline.weight(.medium))
133+
.lineLimit(1)
32134
}
33-
.buttonStyle(.bordered)
135+
}
136+
.padding()
137+
.background(Color.teal.opacity(0.1))
138+
.cornerRadius(12)
139+
.contentShape(Rectangle())
140+
.onTapGesture {
141+
router.navigate(to: .podcastSheet(accountType: accountType, podcastId: podcast.id))
142+
}
143+
.listRowSeparator(.hidden)
144+
.listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
145+
}
146+
}
34147

35-
Spacer()
148+
private struct LiveIndicatorView: View {
149+
var body: some View {
150+
HStack(spacing: 4) {
151+
Image(systemName: "antenna.radiowaves.left.and.right")
152+
Text("Live")
36153
}
37-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
38-
.navigationTitle("XSpace Test")
39-
.navigationBarTitleDisplayMode(.inline)
154+
.font(.caption.weight(.bold))
155+
.foregroundColor(.red)
156+
.padding(.horizontal, 6)
157+
.padding(.vertical, 3)
158+
.background(Color.red.opacity(0.1))
159+
.cornerRadius(6)
40160
}
41161
}

0 commit comments

Comments
 (0)