Changes in UI.

This commit is contained in:
Marcin Czachursk 2023-01-22 21:44:07 +01:00
parent 949234a7a1
commit 92c0bf75ce
17 changed files with 188 additions and 139 deletions

View File

@ -17,7 +17,7 @@ public extension MastodonClientAuthenticated {
return try await downloadJson(Account.self, request: request)
}
func getAccount(for accountId: String) async throws -> Account {
func account(for accountId: String) async throws -> Account {
let request = try Self.request(
for: baseURL,
target: Mastodon.Account.account(accountId),
@ -27,7 +27,7 @@ public extension MastodonClientAuthenticated {
return try await downloadJson(Account.self, request: request)
}
func getRelationship(for accountId: String) async throws -> Relationship? {
func relationships(for accountId: String) async throws -> Relationship? {
let request = try Self.request(
for: baseURL,
target: Mastodon.Account.relationships([accountId]),
@ -38,7 +38,7 @@ public extension MastodonClientAuthenticated {
return relationships.first
}
func getStatuses(for accountId: String,
func statuses(for accountId: String,
onlyMedia: Bool = true,
excludeReplies: Bool = true,
maxId: String? = nil,
@ -114,7 +114,7 @@ public extension MastodonClientAuthenticated {
return try await downloadJson(Relationship.self, request: request)
}
func getFollowers(for accountId: String, page: Int = 1) async throws -> [Account] {
func followers(for accountId: String, page: Int = 1) async throws -> [Account] {
let request = try Self.request(
for: baseURL,
target: Mastodon.Account.followers(accountId, nil, nil, nil, nil, page),
@ -124,7 +124,7 @@ public extension MastodonClientAuthenticated {
return try await downloadJson([Account].self, request: request)
}
func getFollowing(for accountId: String, page: Int = 1) async throws -> [Account] {
func following(for accountId: String, page: Int = 1) async throws -> [Account] {
let request = try Self.request(
for: baseURL,
target: Mastodon.Account.following(accountId, nil, nil, nil, nil, page),

View File

@ -7,7 +7,7 @@
import Foundation
public extension MastodonClientAuthenticated {
func getNotifications(maxId: MaxId? = nil,
func notifications(maxId: MaxId? = nil,
sinceId: SinceId? = nil,
minId: MinId? = nil,
limit: Int? = nil
@ -15,6 +15,7 @@ public extension MastodonClientAuthenticated {
let request = try Self.request(for: baseURL,
target: Mastodon.Notifications.notifications(maxId, sinceId, minId, limit),
withBearerToken: token)
return try await downloadJsonWithLink([Notification].self, request: request)
}
}

View File

@ -7,7 +7,7 @@
import Foundation
public extension MastodonClientAuthenticated {
func read(statusId: EntityId) async throws -> Status {
func status(statusId: EntityId) async throws -> Status {
let request = try Self.request(
for: baseURL,
target: Mastodon.Statuses.status(statusId),

View File

@ -58,7 +58,7 @@ public extension MastodonClientAuthenticated {
return try await downloadJson([Status].self, request: request)
}
func saveMarkers(_ markers: [Mastodon.Markers.Timeline: EntityId]) async throws -> Markers {
func setMarkers(_ markers: [Mastodon.Markers.Timeline: EntityId]) async throws -> Markers {
let request = try Self.request(
for: baseURL,
target: Mastodon.Markers.set(markers),

View File

@ -11,38 +11,38 @@ public class AccountService {
public static let shared = AccountService()
private init() { }
public func getAccount(withId accountId: String, and accountData: AccountData?) async throws -> Account? {
public func account(withId accountId: String, and accountData: AccountData?) async throws -> Account? {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return nil
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getAccount(for: accountId)
return try await client.account(for: accountId)
}
public func getRelationship(withId accountId: String, forUser accountData: AccountData?) async throws -> Relationship? {
public func relationships(withId accountId: String, forUser 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.getRelationship(for: accountId)
return try await client.relationships(for: accountId)
}
public func getStatuses(forAccountId accountId: String,
andContext accountData: AccountData?,
onlyMedia: Bool = true,
excludeReplies: Bool = true,
maxId: String? = nil,
sinceId: String? = nil,
minId: String? = nil,
limit: Int = 40) async throws -> [Status] {
public func statuses(forAccountId accountId: String,
andContext accountData: AccountData?,
onlyMedia: Bool = true,
excludeReplies: Bool = true,
maxId: String? = nil,
sinceId: String? = nil,
minId: String? = nil,
limit: Int = 40) async throws -> [Status] {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return []
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getStatuses(for: accountId,
return try await client.statuses(for: accountId,
onlyMedia: onlyMedia,
excludeReplies: excludeReplies,
maxId: maxId,
@ -105,21 +105,21 @@ public class AccountService {
return try await client.unblock(for: accountId)
}
public func getFollowers(forAccountId accountId: String, andContext accountData: AccountData?, page: Int) async throws -> [Account] {
public func followers(forAccountId accountId: String, andContext accountData: AccountData?, page: Int) async throws -> [Account] {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return []
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getFollowers(for: accountId, page: page)
return try await client.followers(for: accountId, page: page)
}
public func getFollowing(forAccountId accountId: String, andContext accountData: AccountData?, page: Int) async throws -> [Account] {
public func following(forAccountId accountId: String, andContext accountData: AccountData?, page: Int) async throws -> [Account] {
guard let accessToken = accountData?.accessToken, let serverUrl = accountData?.serverUrl else {
return []
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getFollowing(for: accountId, page: page)
return try await client.following(for: accountId, page: page)
}
}

View File

@ -11,7 +11,7 @@ public class NotificationService {
public static let shared = NotificationService()
private init() { }
public func getNotifications(forAccountId accountId: String,
public func notifications(forAccountId accountId: String,
andContext accountData: AccountData?,
maxId: MaxId? = nil,
sinceId: SinceId? = nil,
@ -23,6 +23,6 @@ public class NotificationService {
}
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
return try await client.getNotifications(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit)
return try await client.notifications(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit)
}
}

View File

@ -11,13 +11,13 @@ public class StatusService {
public static let shared = StatusService()
private init() { }
public func getStatus(withId statusId: String, and accountData: AccountData?) async throws -> Status? {
public func status(withId statusId: String, and 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.read(statusId: statusId)
return try await client.status(statusId: statusId)
}
func favourite(statusId: String, accountData: AccountData?) async throws -> Status? {
@ -83,7 +83,7 @@ public class StatusService {
return try await client.new(statusComponents: status)
}
func getComments(for statusId: String, and accountData: AccountData) async throws -> [CommentViewModel] {
func comments(for statusId: String, and accountData: AccountData) async throws -> [CommentViewModel] {
var commentViewModels: [CommentViewModel] = []
let client = MastodonClient(baseURL: accountData.serverUrl).getAuthenticated(token: accountData.accessToken ?? String.empty())

View File

@ -110,12 +110,12 @@ struct AccountsView: View {
private func loadFromApi() async throws -> [Account] {
switch self.listType {
case .followers:
return try await AccountService.shared.getFollowers(
return try await AccountService.shared.followers(
forAccountId: self.entityId,
andContext: self.applicationState.accountData,
page: page)
case .following:
return try await AccountService.shared.getFollowing(
return try await AccountService.shared.following(
forAccountId: self.entityId,
andContext: self.applicationState.accountData,
page: page)

View File

@ -196,7 +196,7 @@ struct MainView: View {
Button {
self.sheet = .compose
} label: {
Image(systemName: "photo.stack")
Image(systemName: "square.and.pencil")
.tint(.mainTextColor)
}

View File

@ -94,7 +94,7 @@ struct NotificationsView: View {
func loadNotifications() async {
do {
let linkable = try await NotificationService.shared.getNotifications(
let linkable = try await NotificationService.shared.notifications(
forAccountId: self.accountId,
andContext: self.applicationState.accountData,
maxId: maxId,
@ -119,7 +119,7 @@ struct NotificationsView: View {
private func loadMoreNotifications() async {
do {
let linkable = try await NotificationService.shared.getNotifications(
let linkable = try await NotificationService.shared.notifications(
forAccountId: self.accountId,
andContext: self.applicationState.accountData,
maxId: self.maxId,
@ -140,7 +140,7 @@ struct NotificationsView: View {
private func loadNewNotifications() async {
do {
let linkable = try await NotificationService.shared.getNotifications(
let linkable = try await NotificationService.shared.notifications(
forAccountId: self.accountId,
andContext: self.applicationState.accountData,
minId: self.minId,
@ -154,9 +154,7 @@ struct NotificationsView: View {
await self.downloadAllImages(notifications: linkable.data)
self.minId = linkable.link?.minId
var downloaded = linkable.data
self.notifications.insert(contentsOf: downloaded, at: 0)
self.notifications.insert(contentsOf: linkable.data, at: 0)
} catch {
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: !Task.isCancelled)
}

View File

@ -41,9 +41,9 @@ struct StatusView: View {
exifCreatedDate: $exifCreatedDate,
exifLens: $exifLens)
.onTapGesture {
// withoutAnimation {
withoutAnimation {
self.showImageViewer.toggle()
// }
}
}
VStack(alignment: .leading) {
@ -119,7 +119,7 @@ struct StatusView: View {
}
// Get status from API.
if let status = try await StatusService.shared.getStatus(withId: self.statusId, and: self.applicationState.accountData) {
if let status = try await StatusService.shared.status(withId: self.statusId, and: self.applicationState.accountData) {
let statusViewModel = StatusViewModel(status: status)
// Download images and recalculate exif data.

View File

@ -45,8 +45,8 @@ struct UserProfileView: View {
return
}
async let relationshipTask = AccountService.shared.getRelationship(withId: self.accountId, forUser: self.applicationState.accountData)
async let accountTask = AccountService.shared.getAccount(withId: self.accountId, and: self.applicationState.accountData)
async let relationshipTask = AccountService.shared.relationships(withId: self.accountId, forUser: self.applicationState.accountData)
async let accountTask = AccountService.shared.account(withId: self.accountId, and: self.applicationState.accountData)
// Wait for download account and relationships.
self.firstLoadFinished = true

View File

@ -13,7 +13,7 @@ struct ImagesViewer: View {
// Opacity usied during close dialog animation.
@State private var opacity = 1.0
private let closeDragDistance = 140.0
private let closeDragDistance = 100.0
// Zoom.
@State private var zoomScale = 1.0
@ -37,7 +37,7 @@ struct ImagesViewer: View {
.tag(attachment.id)
.offset(currentOffset)
.scaleEffect(finalAmount + currentAmount)
.opacity(self.opacity)
// .opacity(self.opacity)
//.gesture((finalAmount + currentAmount) > 1.0 ? dragGesture : nil)
.gesture(dragGesture)
.gesture(magnificationGesture)
@ -51,7 +51,9 @@ struct ImagesViewer: View {
}
private func close() {
dismiss()
withoutAnimation {
dismiss()
}
}
var magnificationGesture: some Gesture {
@ -86,17 +88,22 @@ struct ImagesViewer: View {
let pictureOpacity = (self.closeDragDistance - self.currentOffset.height) / self.closeDragDistance
self.opacity = pictureOpacity >= 0 ? pictureOpacity : 0
} .onEnded { amount in
self.currentOffset = CGSize(width: amount.translation.width + self.accumulatedOffset.width,
let offset = CGSize(width: amount.translation.width + self.accumulatedOffset.width,
height: amount.translation.height + self.accumulatedOffset.height)
self.accumulatedOffset = self.currentOffset
if self.accumulatedOffset.height < self.closeDragDistance {
withAnimation(.default) {
if offset.height < closeDragDistance {
withAnimation(.easeInOut) {
self.currentOffset = CGSize.zero
self.accumulatedOffset = CGSize.zero
self.opacity = 1.0
}
} else {
withAnimation(.easeInOut) {
self.currentOffset = amount.predictedEndTranslation
self.accumulatedOffset = CGSize.zero
self.opacity = 1.0
}
self.close()
}
}
@ -137,10 +144,3 @@ struct ImagesViewer: View {
}
}
}
struct ImagesViewer_Previews: PreviewProvider {
static var previews: some View {
Text("Cos")
// ImagesViewer(statusViewModel: StatusViewModel())
}
}

View File

@ -36,19 +36,7 @@ struct InteractionRow: View {
Spacer()
ActionMenu {
NavigationLink(destination: AccountsView(entityId: statusViewModel.id, listType: .reblogged)
.environmentObject(applicationState)
) {
Label("Reboosted by", systemImage: "person.3.sequence")
}
} label: {
HStack(alignment: .center) {
Image(systemName: self.reblogged ? "paperplane.fill" : "paperplane")
Text("\(self.reblogsCount)")
.font(.caption)
}
} primaryAction: {
ActionButton {
do {
let status = self.reblogged
? try await StatusService.shared.unboost(statusId: self.statusViewModel.id, accountData: self.applicationState.accountData)
@ -66,23 +54,17 @@ struct InteractionRow: View {
} catch {
ErrorService.shared.handle(error, message: "Reboost action failed.", showToastr: true)
}
} label: {
HStack(alignment: .center) {
Image(systemName: self.reblogged ? "paperplane.fill" : "paperplane")
Text("\(self.reblogsCount)")
.font(.caption)
}
}
Spacer()
ActionMenu {
NavigationLink(destination: AccountsView(entityId: statusViewModel.id, listType: .favourited)
.environmentObject(applicationState)
) {
Label("Favourited by", systemImage: "person.3.sequence")
}
} label: {
HStack(alignment: .center) {
Image(systemName: self.favourited ? "hand.thumbsup.fill" : "hand.thumbsup")
Text("\(self.favouritesCount)")
.font(.caption)
}
} primaryAction: {
ActionButton {
do {
let status = self.favourited
? try await StatusService.shared.unfavourite(statusId: self.statusViewModel.id, accountData: self.applicationState.accountData)
@ -100,6 +82,12 @@ struct InteractionRow: View {
} catch {
ErrorService.shared.handle(error, message: "Favourite action failed.", showToastr: true)
}
} label: {
HStack(alignment: .center) {
Image(systemName: self.favourited ? "hand.thumbsup.fill" : "hand.thumbsup")
Text("\(self.favouritesCount)")
.font(.caption)
}
}
Spacer()
@ -120,11 +108,34 @@ struct InteractionRow: View {
Image(systemName: self.bookmarked ? "bookmark.fill" : "bookmark")
}
if let url = statusViewModel.url {
Spacer()
ShareLink(item: url) {
Image(systemName: "square.and.arrow.up")
Spacer()
Menu {
NavigationLink(destination: AccountsView(entityId: statusViewModel.id, listType: .reblogged)
.environmentObject(applicationState)
) {
Label("Reboosted by", systemImage: "paperplane")
}
NavigationLink(destination: AccountsView(entityId: statusViewModel.id, listType: .favourited)
.environmentObject(applicationState)
) {
Label("Favourited by", systemImage: "hand.thumbsup")
}
if let url = statusViewModel.url {
Divider()
Link(destination: url) {
Label("Open in browser", systemImage: "safari")
}
ShareLink(item: url) {
Label("Share post", systemImage: "square.and.arrow.up")
}
}
} label: {
Image(systemName: "gear")
}
}
.font(.title3)

View File

@ -56,7 +56,7 @@ struct CommentsSection: View {
.task {
do {
if let accountData = applicationState.accountData {
self.commentViewModels = try await StatusService.shared.getComments(for: statusId, and: accountData)
self.commentViewModels = try await StatusService.shared.comments(for: statusId, and: accountData)
}
} catch {
ErrorService.shared.handle(error, message: "Comments cannot be downloaded.", showToastr: !Task.isCancelled)

View File

@ -69,7 +69,11 @@ struct UserProfileHeader: View {
Spacer()
self.actionButtons()
if self.applicationState.accountData?.id != self.account.id {
self.otherAccountActionButtons()
} else {
self.profileAccountActionButtons()
}
}
if let note = account.note, !note.isEmpty {
@ -87,62 +91,97 @@ struct UserProfileHeader: View {
}
@ViewBuilder
private func actionButtons() -> some View {
if self.applicationState.accountData?.id != self.account.id {
ActionButton {
await onRelationshipButtonTap()
private func otherAccountActionButtons() -> some View {
ActionButton {
await onRelationshipButtonTap()
} label: {
HStack {
Image(systemName: relationship?.following == true ? "person.badge.minus" : "person.badge.plus")
Text(relationship?.following == true ? "Unfollow" : (relationship?.followedBy == true ? "Follow back" : "Follow"))
}
}
.buttonStyle(.borderedProminent)
.tint(relationship?.following == true ? .dangerColor : .accentColor)
Menu (content: {
if let accountUrl = account.url {
Link(destination: accountUrl) {
Label("Open in browser", systemImage: "safari")
}
ShareLink(item: accountUrl) {
Label("Share", systemImage: "square.and.arrow.up")
}
Divider()
}
Button {
Task {
await onMuteAccount()
}
} label: {
HStack {
Image(systemName: relationship?.following == true ? "person.badge.minus" : "person.badge.plus")
Text(relationship?.following == true ? "Unfollow" : (relationship?.followedBy == true ? "Follow back" : "Follow"))
if self.relationship?.muting == true {
Label("Unute", systemImage: "message.and.waveform.fill")
} else {
Label("Mute", systemImage: "message.and.waveform")
}
}
.buttonStyle(.borderedProminent)
.tint(relationship?.following == true ? .dangerColor : .accentColor)
Menu (content: {
if let accountUrl = account.url {
Link(destination: accountUrl) {
Label("Open link to profile", systemImage: "safari")
}
ShareLink(item: accountUrl) {
Label("Share", systemImage: "square.and.arrow.up")
}
Divider()
Button {
Task {
await onBlockAccount()
}
} label: {
if self.relationship?.blocking == true {
Label("Unblock", systemImage: "hand.raised.fill")
} else {
Label("Block", systemImage: "hand.raised")
}
}
}, label: {
Image(systemName: "gear")
})
.buttonStyle(.borderedProminent)
.tint(.accentColor)
}
@ViewBuilder
private func profileAccountActionButtons() -> some View {
Menu (content: {
if let accountUrl = account.url {
Link(destination: accountUrl) {
Label("Open in browser", systemImage: "safari")
}
Button {
Task {
await onMuteAccount()
}
} label: {
if self.relationship?.muting == true {
Label("Unute", systemImage: "message.and.waveform.fill")
} else {
Label("Mute", systemImage: "message.and.waveform")
}
ShareLink(item: accountUrl) {
Label("Share", systemImage: "square.and.arrow.up")
}
Button {
Task {
await onBlockAccount()
}
} label: {
if self.relationship?.blocking == true {
Label("Unblock", systemImage: "hand.raised.fill")
} else {
Label("Block", systemImage: "hand.raised")
}
Divider()
}
Button {
Task {
// await onMuteAccount()
}
}, label: {
Image(systemName: "person.crop.square.fill")
})
.buttonStyle(.borderedProminent)
.tint(Color.secondaryLabel)
}
} label: {
Label("Favourites", systemImage: "hand.thumbsup")
}
Button {
Task {
// await onMuteAccount()
}
} label: {
Label("Bookmarks", systemImage: "bookmark")
}
}, label: {
Image(systemName: "gear")
})
.buttonStyle(.borderedProminent)
.tint(.accentColor)
}
private func onRelationshipButtonTap() async {

View File

@ -66,7 +66,7 @@ struct UserProfileStatuses: View {
return
}
let statuses = try await AccountService.shared.getStatuses(
let statuses = try await AccountService.shared.statuses(
forAccountId: self.accountId,
andContext: self.applicationState.accountData,
limit: self.defaultLimit)
@ -86,7 +86,7 @@ struct UserProfileStatuses: View {
private func loadMoreStatuses() async throws {
if let lastStatusId = self.statusViewModels.last?.id {
let previousStatuses = try await AccountService.shared.getStatuses(
let previousStatuses = try await AccountService.shared.statuses(
forAccountId: self.accountId,
andContext: self.applicationState.accountData,
maxId: lastStatusId,