Improve user profile/details

This commit is contained in:
Marcin Czachursk 2023-01-05 14:50:48 +01:00
parent 07bc128464
commit d6a63036fb
7 changed files with 157 additions and 5 deletions

View File

@ -24,6 +24,7 @@
F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE42966E160001D9973 /* Color+SystemColors.swift */; };
F8210DE72966E1D1001D9973 /* Color+Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE62966E1D1001D9973 /* Color+Assets.swift */; };
F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */; };
F8210DEC2966F30C001D9973 /* UserFeedbackService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DEB2966F30C001D9973 /* UserFeedbackService.swift */; };
F8341F90295C636C009C8EE6 /* UIImage+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8341F8F295C636C009C8EE6 /* UIImage+Exif.swift */; };
F8341F92295C63BB009C8EE6 /* ImageStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8341F91295C63BB009C8EE6 /* ImageStatus.swift */; };
F83901A6295D8EC000456AE2 /* LabelIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83901A5295D8EC000456AE2 /* LabelIcon.swift */; };
@ -83,6 +84,7 @@
F8210DE42966E160001D9973 /* Color+SystemColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+SystemColors.swift"; sourceTree = "<group>"; };
F8210DE62966E1D1001D9973 /* Color+Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Assets.swift"; sourceTree = "<group>"; };
F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatePlaceholderModifier.swift; sourceTree = "<group>"; };
F8210DEB2966F30C001D9973 /* UserFeedbackService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserFeedbackService.swift; sourceTree = "<group>"; };
F8341F8F295C636C009C8EE6 /* UIImage+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Exif.swift"; sourceTree = "<group>"; };
F8341F91295C63BB009C8EE6 /* ImageStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageStatus.swift; sourceTree = "<group>"; };
F83901A5295D8EC000456AE2 /* LabelIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelIcon.swift; sourceTree = "<group>"; };
@ -290,6 +292,7 @@
F85D4974296407F100751DF7 /* TimelineService.swift */,
F8A93D7F2965FED4001D8331 /* AccountService.swift */,
F8210DE02966D0C4001D9973 /* StatusService.swift */,
F8210DEB2966F30C001D9973 /* UserFeedbackService.swift */,
);
path = Services;
sourceTree = "<group>";
@ -427,6 +430,7 @@
F8A93D802965FED4001D8331 /* AccountService.swift in Sources */,
F866F6AA29605AFA002E8F88 /* SceneDelegate.swift in Sources */,
F85D4973296406E700751DF7 /* BottomRight.swift in Sources */,
F8210DEC2966F30C001D9973 /* UserFeedbackService.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -41,4 +41,15 @@ extension MastodonClientAuthenticated {
let (data, _) = try await urlSession.data(for: request)
return try JSONDecoder().decode([Status].self, from: data)
}
func follow(for accountId: String) async throws -> Relationship {
let request = try Self.request(
for: baseURL,
target: Mastodon.Account.follow(accountId),
withBearerToken: token
)
let (data, _) = try await urlSession.data(for: request)
return try JSONDecoder().decode(Relationship.self, from: data)
}
}

View File

@ -37,4 +37,13 @@ public class AccountService {
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getStatuses(for: accountId)
}
public func follow(forAccountId accountId: String, andContext accountData: AccountData?) async throws -> Relationship? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.follow(for: accountId)
}
}

View File

@ -11,7 +11,57 @@ public class StatusService {
public static let shared = StatusService()
private init() { }
func copy(from status: Status, to statusData: StatusData) {
func favourite(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.favourite(statusId: statusId)
}
func unfavourite(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.unfavourite(statusId: statusId)
}
func boost(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.boost(statusId: statusId)
}
func unboost(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.unboost(statusId: statusId)
}
func bookmark(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.bookmark(statusId: statusId)
}
func unbookmark(statusId: String, accountData: AccountData?) async throws -> Status? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.unbookmark(statusId: statusId)
}
}

View File

@ -0,0 +1,18 @@
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
// Licensed under the MIT License.
//
import SwiftUI
import AVFoundation
public class UserFeedbackService {
public static let shared = UserFeedbackService()
private init() { }
func send() {
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
// AudioServicesPlaySystemSound(1016)
}
}

View File

@ -79,7 +79,19 @@ struct UserProfileView: View {
Spacer()
Button {
// TODO: Folllow/Unfollow.
Task {
do {
if let relationship = try await AccountService.shared.follow(
forAccountId: self.accountId,
andContext: self.applicationState.accountData
) {
UserFeedbackService.shared.send()
self.relationship = relationship
}
} catch {
print("Error \(error.localizedDescription)")
}
}
} label: {
HStack {
Image(systemName: relationship?.following == true ? "person.badge.minus" : "person.badge.plus")

View File

@ -7,12 +7,14 @@
import SwiftUI
struct InteractionRow: View {
@EnvironmentObject var applicationState: ApplicationState
@ObservedObject public var statusData: StatusData
var body: some View {
HStack (alignment: .top) {
Button {
// TODO: Reply.
UserFeedbackService.shared.send()
} label: {
HStack(alignment: .center) {
Image(systemName: "message")
@ -24,7 +26,24 @@ struct InteractionRow: View {
Spacer()
Button {
// TODO: Reboost.
Task {
do {
let status = self.statusData.reblogged
? try await StatusService.shared.unboost(statusId: self.statusData.id, accountData: self.applicationState.accountData)
: try await StatusService.shared.boost(statusId: self.statusData.id, accountData: self.applicationState.accountData)
if let status {
self.statusData.reblogsCount = status.reblogsCount == self.statusData.reblogsCount
? Int32(status.reblogsCount + 1)
: Int32(status.reblogsCount)
self.statusData.reblogged = status.reblogged
UserFeedbackService.shared.send()
}
} catch {
print("Error \(error.localizedDescription)")
}
}
} label: {
HStack(alignment: .center) {
Image(systemName: statusData.reblogged ? "paperplane.fill" : "paperplane")
@ -36,7 +55,24 @@ struct InteractionRow: View {
Spacer()
Button {
// TODO: Favorite.
Task {
do {
let status = self.statusData.favourited
? try await StatusService.shared.unfavourite(statusId: self.statusData.id, accountData: self.applicationState.accountData)
: try await StatusService.shared.favourite(statusId: self.statusData.id, accountData: self.applicationState.accountData)
if let status {
self.statusData.favouritesCount = status.favouritesCount == self.statusData.favouritesCount
? Int32(status.favouritesCount + 1)
: Int32(status.favouritesCount)
self.statusData.favourited = status.favourited
UserFeedbackService.shared.send()
}
} catch {
print("Error \(error.localizedDescription)")
}
}
} label: {
HStack(alignment: .center) {
Image(systemName: statusData.favourited ? "hand.thumbsup.fill" : "hand.thumbsup")
@ -48,7 +84,18 @@ struct InteractionRow: View {
Spacer()
Button {
// TODO: Bookmark.
Task {
do {
let status = self.statusData.bookmarked
? try await StatusService.shared.unbookmark(statusId: self.statusData.id, accountData: self.applicationState.accountData)
: try await StatusService.shared.bookmark(statusId: self.statusData.id, accountData: self.applicationState.accountData)
self.statusData.bookmarked.toggle()
UserFeedbackService.shared.send()
} catch {
print("Error \(error.localizedDescription)")
}
}
} label: {
Image(systemName: statusData.bookmarked ? "bookmark.fill" : "bookmark")
}
@ -57,6 +104,7 @@ struct InteractionRow: View {
Button {
// TODO: Share.
UserFeedbackService.shared.send()
} label: {
Image(systemName: "square.and.arrow.up")
}