Skip to content

Commit 969d054

Browse files
Complete request to follow banner, initial iteration
Contributes to IOS-634
1 parent 58510c5 commit 969d054

9 files changed

Lines changed: 118 additions & 51 deletions

File tree

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/AccountRowView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct AccountRowView: View {
4242
HStack(spacing: doublePadding) {
4343
AccountStatsView(displayType: .largeStacked, accountMetrics: viewModel.account.metrics, onTapOfMetric: nil)
4444
Spacer()
45-
viewModel.relationshipButton.button {
45+
viewModel.relationshipButton.button(isOpaque: false) {
4646
Task {
4747
try await viewModel.doRelationshipButtonAction(navigator: navigator)
4848
}

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/HashtagRowView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct HashtagHeaderView: View {
6565
}
6666
Spacer()
6767
if let isFollowing = viewModel.entity.following {
68-
buttonType.button {
68+
buttonType.button(isOpaque: false) {
6969
guard let user = AuthenticationServiceProvider.shared.currentActiveUser.value else { return }
7070
isUpdating = true
7171
Task {

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/Molecules/RelationshipButtonType.swift

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ enum RelationshipButtonType {
1313
case iDoNotFollowThem(theyFollowMe: Bool, theirAccountIsLocked: Bool)
1414
case iFollowThem(theyFollowMe: Bool)
1515
case iHaveRequestedToFollowThem
16+
case rejectTheirFollowRequest
17+
case acceptTheirFollowRequest
1618
case edit
1719
case hiddenByModerators
1820

@@ -22,6 +24,8 @@ enum RelationshipButtonType {
2224
case unfollow
2325
case unmute
2426
case unblock
27+
case approveFollowRequest
28+
case rejectFollowRequest
2529
case noAction
2630

2731
var mastodonPostMenuAction: MastodonPostMenuAction? {
@@ -34,7 +38,7 @@ enum RelationshipButtonType {
3438
return .unmute
3539
case .unblock:
3640
return .unblockUser
37-
case .noAction, .editProfile:
41+
case .noAction, .editProfile, .approveFollowRequest, .rejectFollowRequest:
3842
return nil
3943
}
4044
}
@@ -49,7 +53,7 @@ enum RelationshipButtonType {
4953
return .unmute
5054
case .unblock:
5155
return .unblockUser
52-
case .noAction, .editProfile:
56+
case .noAction, .editProfile, .approveFollowRequest, .rejectFollowRequest:
5357
return nil
5458
}
5559
}
@@ -101,6 +105,10 @@ enum RelationshipButtonType {
101105
return "iHaveRequestedToFollowThem"
102106
case .hiddenByModerators:
103107
return "hiddenByModerators"
108+
case .acceptTheirFollowRequest:
109+
return "acceptTheirFollowRequest"
110+
case .rejectTheirFollowRequest:
111+
return "rejectTheirFollowRequest"
104112
}
105113
}
106114

@@ -130,6 +138,10 @@ enum RelationshipButtonType {
130138
return nil
131139
case .hiddenByModerators:
132140
return "Show anyway" // TODO: L10n
141+
case .acceptTheirFollowRequest:
142+
return "Accept" // TODO: L10n
143+
case .rejectTheirFollowRequest:
144+
return "Reject" // TODO: L10n
133145
}
134146
}
135147

@@ -149,6 +161,10 @@ enum RelationshipButtonType {
149161
return .unblock
150162
case .hiddenByModerators:
151163
return .noAction
164+
case .acceptTheirFollowRequest:
165+
return .approveFollowRequest
166+
case .rejectTheirFollowRequest:
167+
return .rejectFollowRequest
152168
}
153169
}
154170

@@ -162,55 +178,55 @@ enum RelationshipButtonType {
162178
}
163179
}
164180

165-
@ViewBuilder func button(action: @escaping ()->()) -> some View {
181+
@ViewBuilder func button(isOpaque: Bool, action: @escaping ()->()) -> some View {
166182
switch self {
167183
case .updating:
168184
Button() {
169185
// nothing to do
170186
} label: {
171187
ProgressView().progressViewStyle(.circular)
172188
}
173-
.buttonStyle(RelationshipButtonStyle(self, isLarge: false))
189+
.buttonStyle(RelationshipButtonStyle(self, isLarge: false, isOpaque: isOpaque))
174190
case .error:
175191
Button() {
176192
// nothing to do
177193
} label: {
178194
lightwieghtImageView("exclamationmark.triangle", size: AvatarSize.tiny)
179195
}
180-
.buttonStyle(RelationshipButtonStyle(self, isLarge: false))
196+
.buttonStyle(RelationshipButtonStyle(self, isLarge: false, isOpaque: isOpaque))
181197
default:
182198
if let buttonText = buttonText(isLarge: false) {
183199
Button(buttonText) {
184200
action()
185201
}
186-
.buttonStyle(RelationshipButtonStyle(self, isLarge: false))
202+
.buttonStyle(RelationshipButtonStyle(self, isLarge: false, isOpaque: isOpaque))
187203
}
188204
}
189205
}
190206

191-
@ViewBuilder func largeButton(action: @escaping ()->()) -> some View {
207+
@ViewBuilder func largeButton(isOpaque: Bool, action: @escaping ()->()) -> some View {
192208
switch self {
193209
case .updating:
194210
Button() {
195211
// nothing to do
196212
} label: {
197213
ProgressView().progressViewStyle(.circular)
198214
}
199-
.buttonStyle(RelationshipButtonStyle(self, isLarge: true))
215+
.buttonStyle(RelationshipButtonStyle(self, isLarge: true, isOpaque: isOpaque))
200216
case .error:
201217
Button() {
202218

203219
} label: {
204220
lightwieghtImageView(
205221
"exclamationmark.triangle", size: AvatarSize.tiny)
206222
}
207-
.buttonStyle(RelationshipButtonStyle(self, isLarge: true))
223+
.buttonStyle(RelationshipButtonStyle(self, isLarge: true, isOpaque: isOpaque))
208224
default:
209225
if let buttonText = buttonText(isLarge: true) {
210226
Button(buttonText) {
211227
action()
212228
}
213-
.buttonStyle(RelationshipButtonStyle(self, isLarge: true))
229+
.buttonStyle(RelationshipButtonStyle(self, isLarge: true, isOpaque: isOpaque))
214230
}
215231
}
216232
}

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/NotificationRowView.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ struct NotificationRowView: View {
601601
case .fetching, .unfetched:
602602
ProgressView().progressViewStyle(.circular)
603603
case .relationshipButton(let button):
604-
button.button {
604+
button.button(isOpaque: false) {
605605
viewModel.doAvatarRowButtonAction(navigator: navigator)
606606
}
607607
case .followRequestControls(let controls):
@@ -613,7 +613,7 @@ struct NotificationRowView: View {
613613
// TODO: allow unfollow here?
614614
}
615615
.buttonStyle(
616-
RelationshipButtonStyle(.iFollowThem(theyFollowMe: false), isLarge: false)
616+
RelationshipButtonStyle(.iFollowThem(theyFollowMe: false), isLarge: false, isOpaque: false)
617617
)
618618
.fixedSize()
619619
.accessibilityLabel(L10n.Common.Controls.Friendship.following)
@@ -854,10 +854,12 @@ extension Mastodon.Entity.Status {
854854
struct RelationshipButtonStyle: ButtonStyle {
855855
private let action: RelationshipButtonType.RelationshipAction
856856
private let isLarge: Bool
857+
private let isOpaque: Bool
857858

858-
init(_ relationshipButton: RelationshipButtonType, isLarge: Bool) {
859+
init(_ relationshipButton: RelationshipButtonType, isLarge: Bool, isOpaque: Bool) {
859860
action = relationshipButton.buttonAction
860861
self.isLarge = isLarge
862+
self.isOpaque = isOpaque
861863
}
862864

863865
func makeBody(configuration: Configuration) -> some View {
@@ -869,6 +871,7 @@ struct RelationshipButtonStyle: ButtonStyle {
869871
.padding([.horizontal], 12)
870872
.padding([.vertical], 14)
871873
.background(backgroundColor)
874+
.background(isOpaque ? Color(UIColor.secondarySystemBackground) : Color.clear)
872875
.foregroundStyle(textColor)
873876
.controlSize(.small)
874877
.fontWeight(fontWeight)
@@ -889,9 +892,9 @@ struct RelationshipButtonStyle: ButtonStyle {
889892

890893
private var backgroundColor: Color {
891894
switch action {
892-
case .follow, .editProfile:
895+
case .follow, .editProfile, .approveFollowRequest:
893896
return Asset.Colors.Button.userFollow.swiftUIColor
894-
case .unfollow, .unmute, .unblock:
897+
case .unfollow, .unmute, .unblock, .rejectFollowRequest:
895898
return Asset.Colors.Button.userFollowing.swiftUIColor
896899
case .noAction:
897900
return .secondary.opacity(0.2)
@@ -900,9 +903,9 @@ struct RelationshipButtonStyle: ButtonStyle {
900903

901904
private var textColor: Color {
902905
switch action {
903-
case .follow, .editProfile:
906+
case .follow, .editProfile, .approveFollowRequest:
904907
return .white
905-
case .unfollow, .unmute, .unblock:
908+
case .unfollow, .unmute, .unblock, .rejectFollowRequest:
906909
return Asset.Colors.Button.userFollowingTitle.swiftUIColor
907910
case .noAction:
908911
return Asset.Colors.Button.userFollowingTitle.swiftUIColor
@@ -911,9 +914,9 @@ struct RelationshipButtonStyle: ButtonStyle {
911914

912915
private var fontWeight: SwiftUICore.Font.Weight {
913916
switch action {
914-
case .follow, .editProfile:
917+
case .follow, .editProfile, .approveFollowRequest:
915918
return isLarge ? .bold : .regular
916-
case .unfollow, .unmute, .unblock:
919+
case .unfollow, .unmute, .unblock, .rejectFollowRequest:
917920
return isLarge ? .regular : .light
918921
case .noAction:
919922
return isLarge ? .bold : .regular

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/NotificationRowViewModel.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ extension NotificationRowViewModel {
332332
).value
333333
assert(newRelationship.followedBy == expectedFollowedByResult, "expected to update following relationship after answering follow request")
334334
self.avatarRowAdditionalElement = .followRequestControls(.iHaveAnsweredTheirRequestToFollowMe(didAccept: accept))
335+
let newInfo = MastodonAccount.RelationshipInfo.init(newRelationship, fetchedAt: .now)
336+
FeedCoordinator.shared.publishUpdate(.relationship(.isNotMe(newInfo)))
335337
} catch {
336338
// presentError?(error)
337339
self.avatarRowAdditionalElement = startingAvatarRowRelationshipElement

Mastodon/In Progress New Layout and Datamodel/Common Components/Views/TimelineRowViews/RelationshipViewModel.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010
public private(set) var relationship: MastodonAccount.Relationship? = nil
1111
public var personalNoteEditingState: ProfileView.PersonalNoteEditState?
1212
private var theirAccountIsLocked: Bool?
13-
public var pendingRequestToFollowMe: Bool = true
13+
public var pendingRequestToFollowMe: Bool = false
1414

1515
public func prepareForDisplay(relationship: MastodonAccount.Relationship, theirAccountIsLocked: Bool) {
1616
self.theirAccountIsLocked = theirAccountIsLocked
@@ -20,6 +20,9 @@ import SwiftUI
2020
guard let entity = info?._legacyEntity else { break }
2121
let updatedButton = RelationshipButtonType(relationship: entity, theirAccountIsLocked: theirAccountIsLocked)
2222
button = updatedButton
23+
withAnimation {
24+
pendingRequestToFollowMe = info?.theyHaveRequestedToFollowMe ?? false
25+
}
2326
case .isMe:
2427
button = .edit
2528
}
@@ -57,10 +60,32 @@ import SwiftUI
5760
throw AppError.unexpected(
5861
"action attempted for relationship element that has no action"
5962
)
63+
64+
case .approveFollowRequest:
65+
try await doAnswerFollowRequest(true)
66+
67+
case .rejectFollowRequest:
68+
try await doAnswerFollowRequest(false)
6069
}
6170
} catch {
6271
button = currentState
6372
throw error
6473
}
6574
}
75+
76+
private func doAnswerFollowRequest(_ accept: Bool) async throws {
77+
guard let accountID = relationship?.info?.id,
78+
let authBox = AuthenticationServiceProvider.shared.currentActiveUser
79+
.value
80+
else { return }
81+
let expectedFollowedByResult = accept
82+
let newRelationship = try await APIService.shared.followRequest(
83+
userID: accountID,
84+
query: accept ? .accept : .reject,
85+
authenticationBox: authBox
86+
).value
87+
assert(newRelationship.followedBy == expectedFollowedByResult, "expected to update following relationship after answering follow request")
88+
let newInfo = MastodonAccount.RelationshipInfo.init(newRelationship, fetchedAt: .now)
89+
FeedCoordinator.shared.publishUpdate(.relationship(.isNotMe(newInfo)))
90+
}
6691
}

Mastodon/In Progress New Layout and Datamodel/GenericMastodonPost and Subclasses/MastodonAccount.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ extension MastodonAccount {
242242
let iHideTheirBoosts: Bool
243243
let theyFollowMe: Bool?
244244
let iHaveRequestedToFollowThem: Bool
245+
let theyHaveRequestedToFollowMe: Bool?
245246
let iAmMutingThem: Bool
246247
let iAmBlockingTheirDomain: Bool
247248
let iAmBlockingThem: Bool
@@ -256,6 +257,7 @@ extension MastodonAccount {
256257
iHideTheirBoosts = !entity.showingReblogs
257258
theyFollowMe = entity.followedBy
258259
iHaveRequestedToFollowThem = entity.requested
260+
theyHaveRequestedToFollowMe = entity.requestedBy
259261
iAmMutingThem = entity.muting
260262
iAmBlockingThem = entity.blocking
261263
iAmBlockingTheirDomain = entity.domainBlocking

0 commit comments

Comments
 (0)