Skip to content

Commit 5a450f1

Browse files
authored
Merge pull request #4189 from anyproto/ios-5387-space-hub-coordinator-a-lot-if-sheet-methods-make-body-very
iOS-5387 Space View | improve diff
2 parents 3596676 + 92833f8 commit 5a450f1

File tree

15 files changed

+703
-497
lines changed

15 files changed

+703
-497
lines changed

Anytype/Sources/PresentationLayer/Modules/SpaceHub/SpaceHubDropDelegate.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,30 @@ import AnytypeCore
55

66
struct SpaceHubDropDelegate: DropDelegate {
77

8-
let destinationItem: ParticipantSpaceViewDataWithPreview
8+
let destinationSpaceViewId: String?
99
@Binding var allSpaces: [ParticipantSpaceViewDataWithPreview]?
10-
@Binding var draggedItem: ParticipantSpaceViewDataWithPreview?
10+
@Binding var draggedSpaceViewId: String?
1111
@Binding var initialIndex: Int?
1212

1313
func dropUpdated(info: DropInfo) -> DropProposal? {
1414
return DropProposal(operation: .move)
1515
}
1616

1717
func performDrop(info: DropInfo) -> Bool {
18-
guard let allSpaces, draggedItem.isNotNil, let initialIndex else { return false }
18+
guard let allSpaces, draggedSpaceViewId.isNotNil, let initialIndex else { return false }
1919

20-
guard let finalIndex = allSpaces.firstIndex(of: destinationItem) else { return false }
20+
guard let finalIndex = allSpaces.firstIndex(where: { $0.spaceView.id == destinationSpaceViewId }) else { return false }
2121
guard finalIndex != initialIndex else { return false }
2222

23-
self.draggedItem = nil
23+
self.draggedSpaceViewId = nil
2424
self.initialIndex = nil
2525
return true
2626
}
2727

2828
func dropEntered(info: DropInfo) {
29-
guard var allSpaces, let draggedItem else { return }
30-
guard let fromIndex = allSpaces.firstIndex(where: { $0.space.id == draggedItem.space.id } ) else { return }
31-
guard let toIndex = allSpaces.firstIndex(where: { $0.space.id == destinationItem.space.id } ) else { return }
29+
guard var allSpaces, let draggedSpaceViewId else { return }
30+
guard let fromIndex = allSpaces.firstIndex(where: { $0.space.spaceView.id == draggedSpaceViewId } ) else { return }
31+
guard let toIndex = allSpaces.firstIndex(where: { $0.space.spaceView.id == destinationSpaceViewId } ) else { return }
3232

3333
guard fromIndex != toIndex else { return }
3434

@@ -52,7 +52,7 @@ struct SpaceHubDropDelegate: DropDelegate {
5252
let spaceOrderService = Container.shared.spaceOrderService()
5353

5454
try await spaceOrderService.setOrder(
55-
spaceViewIdMoved: draggedItem.spaceView.id, newOrder: newOrder
55+
spaceViewIdMoved: draggedSpaceViewId, newOrder: newOrder
5656
)
5757
AnytypeAnalytics.instance().logReorderSpace()
5858
}

Anytype/Sources/PresentationLayer/Modules/SpaceHub/SpaceHubView.swift

Lines changed: 10 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ import DesignKit
55

66
struct SpaceHubView: View {
77
@State private var model: SpaceHubViewModel
8-
@State private var draggedSpace: ParticipantSpaceViewDataWithPreview?
9-
@State private var draggedInitialIndex: Int?
10-
@State private var vaultBackToRootsToggle = FeatureFlags.vaultBackToRoots
118

129
private var namespace: Namespace.ID
1310

@@ -34,53 +31,30 @@ struct SpaceHubView: View {
3431
@ViewBuilder
3532
private var content: some View {
3633
Group {
37-
if let spaces = model.spaces {
38-
spacesView(spaces)
34+
if model.dataLoaded {
35+
spacesView()
3936
} else {
4037
EmptyView() // Do not show empty state view if we do not receive data yet
4138
}
4239

4340
Spacer()
4441
}
4542
.ignoresSafeArea(edges: .bottom)
46-
.animation(.default, value: model.spaces)
4743
}
4844

49-
private func spacesView(_ spaces: [ParticipantSpaceViewDataWithPreview]) -> some View {
45+
private func spacesView() -> some View {
5046
NavigationStack {
51-
Group {
52-
if spaces.isEmpty {
53-
emptyStateView
54-
} else if model.filteredSpaces.isNotEmpty {
55-
scrollView
56-
} else {
57-
SpaceHubSearchEmptySpaceView()
47+
SpaceHubList(model: model)
48+
.navigationTitle(Loc.myChannels)
49+
.navigationBarTitleDisplayMode(.inline)
50+
.toolbar { toolbarItems }
51+
.searchable(text: $model.searchText)
52+
.onChange(of: model.searchText) {
53+
model.searchTextUpdated()
5854
}
59-
}
60-
.navigationTitle(Loc.myChannels)
61-
.navigationBarTitleDisplayMode(.inline)
62-
.toolbar { toolbarItems }
63-
.searchable(text: $model.searchText)
64-
.onChange(of: model.searchText) {
65-
model.searchTextUpdated()
66-
}
6755
}.tint(Color.Text.secondary)
6856
}
6957

70-
private var scrollView: some View {
71-
ScrollView {
72-
VStack(spacing: vaultBackToRootsToggle ? 8 : 0) {
73-
HomeUpdateSubmoduleView().padding(8)
74-
75-
ForEach(model.filteredSpaces) {
76-
spaceCard($0)
77-
}
78-
79-
Spacer.fixedHeight(40)
80-
}
81-
}
82-
}
83-
8458
private var toolbarItems: some ToolbarContent {
8559
SpaceHubToolbar(
8660
showLoading: model.showLoading,
@@ -95,54 +69,6 @@ struct SpaceHubView: View {
9569
}
9670
)
9771
}
98-
99-
private var emptyStateView: some View {
100-
SpaceHubEmptyStateView {
101-
model.onTapCreateSpace()
102-
}
103-
}
104-
105-
private func spaceCard(_ space: ParticipantSpaceViewDataWithPreview) -> some View {
106-
SpaceCard(
107-
spaceData: space,
108-
wallpaper: model.wallpapers[space.spaceView.targetSpaceId] ?? .default,
109-
draggedSpace: $draggedSpace,
110-
onTap: {
111-
model.onSpaceTap(spaceId: space.spaceView.targetSpaceId)
112-
},
113-
onTapCopy: {
114-
model.copySpaceInfo(spaceView: space.spaceView)
115-
},
116-
onTapMute: {
117-
model.muteSpace(spaceView: space.spaceView)
118-
},
119-
onTapPin: {
120-
try await model.pin(spaceView: space.spaceView)
121-
},
122-
onTapUnpin: {
123-
try await model.unpin(spaceView: space.spaceView)
124-
},
125-
onTapSettings: {
126-
model.openSpaceSettings(spaceId: space.spaceView.targetSpaceId)
127-
},
128-
onTapDelete: {
129-
model.onDeleteSpace(spaceId: space.spaceView.targetSpaceId)
130-
}
131-
)
132-
.equatable()
133-
.padding(.horizontal, vaultBackToRootsToggle ? 16 : 0)
134-
.if(space.spaceView.isPinned) {
135-
$0.onDrop(
136-
of: [.text],
137-
delegate: SpaceHubDropDelegate(
138-
destinationItem: space,
139-
allSpaces: $model.spaces,
140-
draggedItem: $draggedSpace,
141-
initialIndex: $draggedInitialIndex
142-
)
143-
)
144-
}
145-
}
14672
}
14773

14874
#Preview {

Anytype/Sources/PresentationLayer/Modules/SpaceHub/SpaceHubViewModel.swift

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import Loc
88
@MainActor
99
@Observable
1010
final class SpaceHubViewModel {
11+
1112
var spaces: [ParticipantSpaceViewDataWithPreview]?
13+
var dataLoaded = false
1214
var searchText: String = ""
13-
14-
var filteredSpaces: [ParticipantSpaceViewDataWithPreview] = []
15+
var filteredSpaces: [SpaceCardModel] = []
1516

1617
var wallpapers: [String: SpaceWallpaperType] = [:]
1718

@@ -23,7 +24,6 @@ final class SpaceHubViewModel {
2324

2425
@ObservationIgnored
2526
private weak var output: (any SpaceHubModuleOutput)?
26-
2727

2828
@Injected(\.userDefaultsStorage) @ObservationIgnored
2929
private var userDefaults: any UserDefaultsStorageProtocol
@@ -39,6 +39,8 @@ final class SpaceHubViewModel {
3939
private var pushNotificationsSystemSettingsBroadcaster: any PushNotificationsSystemSettingsBroadcasterProtocol
4040
@Injected(\.workspaceService) @ObservationIgnored
4141
private var workspaceService: any WorkspaceServiceProtocol
42+
@Injected(\.spaceCardModelBuilder)@ObservationIgnored
43+
private var spaceCardModelBuilder: any SpaceCardModelBuilderProtocol
4244

4345
init(output: (any SpaceHubModuleOutput)?) {
4446
self.output = output
@@ -62,31 +64,33 @@ final class SpaceHubViewModel {
6264
}
6365

6466

65-
func copySpaceInfo(spaceView: SpaceView) {
67+
func copySpaceInfo(spaceViewId: String) {
68+
guard let spaceView = spaces?.first(where: { $0.spaceView.id == spaceViewId })?.spaceView else { return }
6669
UIPasteboard.general.string = String(describing: spaceView)
6770
}
6871

69-
func muteSpace(spaceView: SpaceView) {
72+
func muteSpace(spaceViewId: String) {
73+
guard let spaceView = spaces?.first(where: { $0.spaceView.id == spaceViewId })?.spaceView else { return }
7074
let isUnmutedAll = spaceView.pushNotificationMode.isUnmutedAll
7175
spaceMuteData = SpaceMuteData(
7276
spaceId: spaceView.targetSpaceId,
7377
mode: isUnmutedAll ? .mentions : .all
7478
)
7579
}
7680

77-
func pin(spaceView: SpaceView) async throws {
81+
func pin(spaceViewId: String) async throws {
7882
guard let spaces else { return }
7983
let pinnedSpaces = spaces.filter { $0.spaceView.isPinned }
84+
85+
var newOrder = pinnedSpaces.filter { $0.spaceView.id != spaceViewId }.map(\.spaceView.id)
86+
newOrder.insert(spaceViewId, at: 0)
8087

81-
var newOrder = pinnedSpaces.filter { $0.spaceView.id != spaceView.id }.map(\.spaceView.id)
82-
newOrder.insert(spaceView.id, at: 0)
83-
84-
try await spaceOrderService.setOrder(spaceViewIdMoved: spaceView.id, newOrder: newOrder)
88+
try await spaceOrderService.setOrder(spaceViewIdMoved: spaceViewId, newOrder: newOrder)
8589
AnytypeAnalytics.instance().logPinSpace()
8690
}
8791

88-
func unpin(spaceView: SpaceView) async throws {
89-
try await spaceOrderService.unsetOrder(spaceViewId: spaceView.id)
92+
func unpin(spaceViewId: String) async throws {
93+
try await spaceOrderService.unsetOrder(spaceViewId: spaceViewId)
9094
AnytypeAnalytics.instance().logUnpinSpace()
9195
}
9296

@@ -120,15 +124,18 @@ final class SpaceHubViewModel {
120124
}
121125

122126
func searchTextUpdated() {
123-
updateFilteredSpaces()
127+
Task {
128+
await updateFilteredSpaces()
129+
}
124130
}
125131

126132
// MARK: - Private
127133
private func subscribeOnSpaces() async {
128134
for await spaces in await spaceHubSpacesStorage.spacesStream {
129135
self.spaces = spaces.sorted(by: sortSpacesForPinnedFeature)
130136
showLoading = spaces.contains { $0.spaceView.isLoading }
131-
updateFilteredSpaces()
137+
await updateFilteredSpaces()
138+
self.dataLoaded = spaces.isNotEmpty
132139
}
133140
}
134141

@@ -207,20 +214,21 @@ final class SpaceHubViewModel {
207214
}
208215
}
209216

210-
private func updateFilteredSpaces() {
211-
217+
private func updateFilteredSpaces() async {
212218
guard let spaces else {
213219
filteredSpaces = []
214220
return
215221
}
216222

217-
guard !searchText.isEmpty else {
218-
filteredSpaces = spaces
219-
return
223+
let spacesToFilter: [ParticipantSpaceViewDataWithPreview]
224+
if searchText.isEmpty {
225+
spacesToFilter = spaces
226+
} else {
227+
spacesToFilter = spaces.filter { space in
228+
space.spaceView.name.localizedCaseInsensitiveContains(searchText)
229+
}
220230
}
221231

222-
filteredSpaces = spaces.filter { space in
223-
space.spaceView.name.localizedCaseInsensitiveContains(searchText)
224-
}
232+
self.filteredSpaces = await spaceCardModelBuilder.build(from: spacesToFilter, wallpapers: wallpapers)
225233
}
226234
}

0 commit comments

Comments
 (0)