diff --git a/ClientKit/Sources/ClientKit/Client+Timeline.swift b/ClientKit/Sources/ClientKit/Client+Timeline.swift index 41b1383..e70305c 100644 --- a/ClientKit/Sources/ClientKit/Client+Timeline.swift +++ b/ClientKit/Sources/ClientKit/Client+Timeline.swift @@ -12,8 +12,9 @@ extension Client { public func getHomeTimeline(maxId: String? = nil, sinceId: String? = nil, minId: String? = nil, - limit: Int = 40) async throws -> [Status] { - return try await pixelfedClient.getHomeTimeline(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit) + limit: Int = 40, + includeReblogs: Bool? = nil) async throws -> [Status] { + return try await pixelfedClient.getHomeTimeline(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit, includeReblogs: includeReblogs) } public func getStatuses(local: Bool? = nil, diff --git a/ClientKit/Sources/ClientKit/Models/StatusModel.swift b/ClientKit/Sources/ClientKit/Models/StatusModel.swift index 17f9252..5cd7564 100644 --- a/ClientKit/Sources/ClientKit/Models/StatusModel.swift +++ b/ClientKit/Sources/ClientKit/Models/StatusModel.swift @@ -45,7 +45,7 @@ public class StatusModel: ObservableObject { // If status has been rebloged we are saving orginal status here. let orginalStatus = status.reblog ?? status - self.id = orginalStatus.id + self.id = status.id self.content = orginalStatus.content self.uri = orginalStatus.uri self.url = orginalStatus.url diff --git a/CoreData/ApplicationSettings+CoreDataProperties.swift b/CoreData/ApplicationSettings+CoreDataProperties.swift index 0ecf351..1c9a977 100644 --- a/CoreData/ApplicationSettings+CoreDataProperties.swift +++ b/CoreData/ApplicationSettings+CoreDataProperties.swift @@ -34,6 +34,7 @@ extension ApplicationSettings { @NSManaged public var showAltIconOnTimeline: Bool @NSManaged public var warnAboutMissingAlt: Bool @NSManaged public var showGridOnUserProfile: Bool + @NSManaged public var showReboostedStatuses: Bool @NSManaged public var customNavigationMenuItem1: Int32 @NSManaged public var customNavigationMenuItem2: Int32 diff --git a/CoreData/ApplicationSettingsHandler.swift b/CoreData/ApplicationSettingsHandler.swift index edc87ea..a2e5541 100644 --- a/CoreData/ApplicationSettingsHandler.swift +++ b/CoreData/ApplicationSettingsHandler.swift @@ -59,6 +59,7 @@ class ApplicationSettingsHandler { applicationState.showAltIconOnTimeline = defaultSettings.showAltIconOnTimeline applicationState.warnAboutMissingAlt = defaultSettings.warnAboutMissingAlt applicationState.showGridOnUserProfile = defaultSettings.showGridOnUserProfile + applicationState.showReboostedStatuses = defaultSettings.showReboostedStatuses if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) { applicationState.menuPosition = menuPosition @@ -197,6 +198,12 @@ class ApplicationSettingsHandler { CoreDataHandler.shared.save() } + func set(showReboostedStatuses: Bool) { + let defaultSettings = self.get() + defaultSettings.showReboostedStatuses = showReboostedStatuses + CoreDataHandler.shared.save() + } + private func createApplicationSettingsEntity(viewContext: NSManagedObjectContext? = nil) -> ApplicationSettings { let context = viewContext ?? CoreDataHandler.shared.container.viewContext return ApplicationSettings(context: context) diff --git a/CoreData/StatusData+Status.swift b/CoreData/StatusData+Status.swift index b0f7385..bd7c17a 100644 --- a/CoreData/StatusData+Status.swift +++ b/CoreData/StatusData+Status.swift @@ -12,7 +12,8 @@ extension StatusData { if let reblog = status.reblog { self.copyFrom(reblog) - self.rebloggedStatusId = status.id + self.id = status.id + self.rebloggedStatusId = reblog.id self.rebloggedAccountAvatar = status.account.avatar self.rebloggedAccountDisplayName = status.account.displayName self.rebloggedAccountId = status.account.id diff --git a/CoreData/Vernissage.xcdatamodeld/.xccurrentversion b/CoreData/Vernissage.xcdatamodeld/.xccurrentversion index a37b6e9..e6d648f 100644 --- a/CoreData/Vernissage.xcdatamodeld/.xccurrentversion +++ b/CoreData/Vernissage.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Vernissage-014.xcdatamodel + Vernissage-015.xcdatamodel diff --git a/CoreData/Vernissage.xcdatamodeld/Vernissage-015.xcdatamodel/contents b/CoreData/Vernissage.xcdatamodeld/Vernissage-015.xcdatamodel/contents new file mode 100644 index 0000000..f430ade --- /dev/null +++ b/CoreData/Vernissage.xcdatamodeld/Vernissage-015.xcdatamodel/contents @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift b/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift index dbdfbb2..9049cef 100644 --- a/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift @@ -107,6 +107,9 @@ public class ApplicationState: ObservableObject { /// Show grid of photos on user profile. @Published public var showGridOnUserProfile = false + /// Show reboosted statuses on home timeline. + @Published public var showReboostedStatuses = false + public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) { self.account = accountModel self.lastSeenStatusId = lastSeenStatusId diff --git a/Localization/en.lproj/Localizable.strings b/Localization/en.lproj/Localizable.strings index 311fdda..d404952 100644 --- a/Localization/en.lproj/Localizable.strings +++ b/Localization/en.lproj/Localizable.strings @@ -240,6 +240,8 @@ "settings.title.showAltTextOnTimeline" = "ALT icon will be displayed on timelines"; "settings.title.warnAboutMissingAltTitle" = "Warn of missing ALT text"; "settings.title.warnAboutMissingAltDescription" = "A warning about missing ALT texts will be displayed before publishing new post."; +"settings.title.enableReboostOnTimeline" = "Show boosted statuses"; +"settings.title.enableReboostOnTimelineDescription" = "Boosted statuses will be visible on your home timeline."; // Mark: Signin view. "signin.navigationBar.title" = "Sign in to Pixelfed"; diff --git a/Localization/eu.lproj/Localizable.strings b/Localization/eu.lproj/Localizable.strings index 7363d4d..8dbe06c 100644 --- a/Localization/eu.lproj/Localizable.strings +++ b/Localization/eu.lproj/Localizable.strings @@ -240,6 +240,8 @@ "settings.title.showAltTextOnTimeline" = "ALT ikurra (deskribapena edo testu alternatiboa dagoenaren seinale) denbora-lerroan erakutsiko da"; "settings.title.warnAboutMissingAltTitle" = "Abisatu ALT ahaztu bazait"; "settings.title.warnAboutMissingAltDescription" = "Irudiren batek deskribapenik ez badu, argitaratu baino lehen abisua erakutsiko da."; +"settings.title.enableReboostOnTimeline" = "Show boosted statuses"; +"settings.title.enableReboostOnTimelineDescription" = "Boosted statuses will be visible on your home timeline."; // Mark: Signin view. "signin.navigationBar.title" = "Hasi saioa Pixelfed-en"; diff --git a/Localization/fr.lproj/Localizable.strings b/Localization/fr.lproj/Localizable.strings index 0718e55..472244d 100644 --- a/Localization/fr.lproj/Localizable.strings +++ b/Localization/fr.lproj/Localizable.strings @@ -240,6 +240,8 @@ "settings.title.showAltTextOnTimeline" = "L'icône ALT sera affichée sur la timeline"; "settings.title.warnAboutMissingAltTitle" = "Avertir de l'absence de texte ALT"; "settings.title.warnAboutMissingAltDescription" = "Un avertissement concernant les textes ALT manquants sera affiché avant la publication d'un nouveau message."; +"settings.title.enableReboostOnTimeline" = "Show boosted statuses"; +"settings.title.enableReboostOnTimelineDescription" = "Boosted statuses will be visible on your home timeline."; // Mark: Signin view. "signin.navigationBar.title" = "Se connecter à Pixelfed"; diff --git a/Localization/pl.lproj/Localizable.strings b/Localization/pl.lproj/Localizable.strings index 245aa82..351a159 100644 --- a/Localization/pl.lproj/Localizable.strings +++ b/Localization/pl.lproj/Localizable.strings @@ -240,6 +240,8 @@ "settings.title.showAltTextOnTimeline" = "Ikony ALT będą widonczne na osiach zdjęć"; "settings.title.warnAboutMissingAltTitle" = "Ostrzeganie o brakującym tekście ALT"; "settings.title.warnAboutMissingAltDescription" = "Ostrzeżenie o brakujących tekstach ALT będzie wyświetlane przed opublikowaniem nowego statusu."; +"settings.title.enableReboostOnTimeline" = "Wyświetl podbite statusy"; +"settings.title.enableReboostOnTimelineDescription" = "Podbite statusy będą widoczne na twojej osi czasu."; // Mark: Signin view. "signin.navigationBar.title" = "Zaloguj się do Pixelfed"; diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Timelines.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Timelines.swift index fcd0127..1d387b8 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Timelines.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Timelines.swift @@ -11,11 +11,12 @@ public extension PixelfedClientAuthenticated { maxId: EntityId? = nil, sinceId: EntityId? = nil, minId: EntityId? = nil, - limit: Int? = nil) async throws -> [Status] { + limit: Int? = nil, + includeReblogs: Bool? = nil) async throws -> [Status] { let request = try Self.request( for: baseURL, - target: Pixelfed.Timelines.home(maxId, sinceId, minId, limit), + target: Pixelfed.Timelines.home(maxId, sinceId, minId, limit, includeReblogs), withBearerToken: token ) diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift index b7cbfad..14dc579 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift @@ -8,7 +8,7 @@ import Foundation extension Pixelfed { public enum Timelines { - case home(MaxId?, SinceId?, MinId?, Limit?) + case home(MaxId?, SinceId?, MinId?, Limit?, Bool?) case pub(Bool?, Bool?, Bool?, MaxId?, SinceId?, MinId?, Limit?) case tag(String, Bool?, Bool?, Bool?, MaxId?, SinceId?, MinId?, Limit?) } @@ -43,6 +43,7 @@ extension Pixelfed.Timelines: TargetType { var local: Bool? var remote: Bool? var onlyMedia: Bool? + var includeReblogs: Bool? var maxId: MaxId? var sinceId: SinceId? var minId: MinId? @@ -58,34 +59,46 @@ extension Pixelfed.Timelines: TargetType { sinceId = paramSinceId minId = paramMinId limit = paramLimit - case .home(let paramMaxId, let paramSinceId, let paramMinId, let paramLimit): + case .home(let paramMaxId, let paramSinceId, let paramMinId, let paramLimit, let paramIncludeReblogs): maxId = paramMaxId sinceId = paramSinceId minId = paramMinId limit = paramLimit + includeReblogs = paramIncludeReblogs } if let maxId { params.append(("max_id", maxId)) } + if let sinceId { params.append(("since_id", sinceId)) } + if let minId { params.append(("min_id", minId)) } + if let limit { params.append(("limit", "\(limit)")) } + if let local { params.append(("local", local.asString)) } + if let remote { params.append(("remote", remote.asString)) } + if let onlyMedia { params.append(("only_media", onlyMedia.asString)) } + + if let includeReblogs, includeReblogs == true { + params.append(("include_reblogs", includeReblogs.asString)) + } + return params } diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj index e6848eb..aa7f446 100644 --- a/Vernissage.xcodeproj/project.pbxproj +++ b/Vernissage.xcodeproj/project.pbxproj @@ -332,6 +332,7 @@ F878842129A4A4E3003CFAD2 /* AppMetadataService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMetadataService.swift; sourceTree = ""; }; F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationSession.swift; sourceTree = ""; }; F87AEB962986D16D00434FB6 /* AuthorisationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorisationError.swift; sourceTree = ""; }; + F880EECE2AC70A2B00C09C31 /* Vernissage-015.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-015.xcdatamodel"; sourceTree = ""; }; F883401F29B62AE900C3E096 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; F88AB05229B3613900345EDE /* PhotoUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoUrl.swift; sourceTree = ""; }; F88AB05429B3626300345EDE /* ImageGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGrid.swift; sourceTree = ""; }; @@ -1805,6 +1806,7 @@ F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + F880EECE2AC70A2B00C09C31 /* Vernissage-015.xcdatamodel */, F8206A032A06547600E19412 /* Vernissage-014.xcdatamodel */, F865B4D42A0252FB008ACDFC /* Vernissage-013.xcdatamodel */, F8EF3C8B29FC3A5F00CBFF7C /* Vernissage-012.xcdatamodel */, @@ -1821,7 +1823,7 @@ F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */, F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */, ); - currentVersion = F8206A032A06547600E19412 /* Vernissage-014.xcdatamodel */; + currentVersion = F880EECE2AC70A2B00C09C31 /* Vernissage-015.xcdatamodel */; path = Vernissage.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Vernissage/Services/HomeTimelineService.swift b/Vernissage/Services/HomeTimelineService.swift index a2b78c9..b8ea88f 100644 --- a/Vernissage/Services/HomeTimelineService.swift +++ b/Vernissage/Services/HomeTimelineService.swift @@ -20,7 +20,7 @@ public class HomeTimelineService { private let imagePrefetcher = ImagePrefetcher(destination: .diskCache) @MainActor - public func loadOnBottom(for account: AccountModel) async throws -> Int { + public func loadOnBottom(for account: AccountModel, includeReblogs: Bool) async throws -> Int { // Load data from API and operate on CoreData on background context. let backgroundContext = CoreDataHandler.shared.newBackgroundContext() @@ -32,7 +32,7 @@ public class HomeTimelineService { } // Load data on bottom of the list. - let allStatusesFromApi = try await self.load(for: account, on: backgroundContext, maxId: oldestStatus.id) + let allStatusesFromApi = try await self.load(for: account, includeReblogs: includeReblogs, on: backgroundContext, maxId: oldestStatus.id) // Save data into database. CoreDataHandler.shared.save(viewContext: backgroundContext) @@ -45,7 +45,7 @@ public class HomeTimelineService { } @MainActor - public func refreshTimeline(for account: AccountModel, updateLastSeenStatus: Bool = false) async throws -> String? { + public func refreshTimeline(for account: AccountModel, includeReblogs: Bool, updateLastSeenStatus: Bool = false) async throws -> String? { // Load data from API and operate on CoreData on background context. let backgroundContext = CoreDataHandler.shared.newBackgroundContext() @@ -55,7 +55,7 @@ public class HomeTimelineService { // Refresh/load home timeline (refreshing on top downloads always first 40 items). // When Apple introduce good way to show new items without scroll to top then we can change that method. - let allStatusesFromApi = try await self.refresh(for: account, on: backgroundContext) + let allStatusesFromApi = try await self.refresh(for: account, includeReblogs: includeReblogs, on: backgroundContext) // Update last seen status. if let lastSeenStatusId, updateLastSeenStatus == true { @@ -107,7 +107,7 @@ public class HomeTimelineService { CoreDataHandler.shared.save() } - public func amountOfNewStatuses(for account: AccountModel) async -> Int { + public func amountOfNewStatuses(for account: AccountModel, includeReblogs: Bool) async -> Int { guard let accessToken = account.accessToken else { return 0 } @@ -128,7 +128,7 @@ public class HomeTimelineService { // There can be more then 40 newest statuses, that's why we have to sometimes send more then one request. while true { do { - let downloadedStatuses = try await client.getHomeTimeline(minId: newestStatusId, limit: self.defaultAmountOfDownloadedStatuses) + let downloadedStatuses = try await client.getHomeTimeline(minId: newestStatusId, limit: self.defaultAmountOfDownloadedStatuses, includeReblogs: includeReblogs) guard let firstStatus = downloadedStatuses.first else { break } @@ -147,14 +147,14 @@ public class HomeTimelineService { return amountOfStatuses } - private func refresh(for account: AccountModel, on backgroundContext: NSManagedObjectContext) async throws -> [Status] { + private func refresh(for account: AccountModel, includeReblogs: Bool, on backgroundContext: NSManagedObjectContext) async throws -> [Status] { guard let accessToken = account.accessToken else { return [] } // Retrieve statuses from API. let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken) - let statuses = try await client.getHomeTimeline(limit: self.defaultAmountOfDownloadedStatuses) + let statuses = try await client.getHomeTimeline(limit: self.defaultAmountOfDownloadedStatuses, includeReblogs: includeReblogs) // Update all existing statuses in database. for status in statuses { @@ -207,6 +207,7 @@ public class HomeTimelineService { } private func load(for account: AccountModel, + includeReblogs: Bool, on backgroundContext: NSManagedObjectContext, minId: String? = nil, maxId: String? = nil @@ -217,7 +218,7 @@ public class HomeTimelineService { // Retrieve statuses from API. let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken) - let statuses = try await client.getHomeTimeline(maxId: maxId, minId: minId, limit: self.defaultAmountOfDownloadedStatuses) + let statuses = try await client.getHomeTimeline(maxId: maxId, minId: minId, limit: self.defaultAmountOfDownloadedStatuses, includeReblogs: includeReblogs) // Save statuses in database. try await self.add(statuses, for: account, on: backgroundContext) diff --git a/Vernissage/VernissageApp.swift b/Vernissage/VernissageApp.swift index d4e63c8..75a7d49 100644 --- a/Vernissage/VernissageApp.swift +++ b/Vernissage/VernissageApp.swift @@ -204,7 +204,8 @@ struct VernissageApp: App { private func calculateNewPhotosInBackground() async { if let account = self.applicationState.account { - self.applicationState.amountOfNewStatuses = await HomeTimelineService.shared.amountOfNewStatuses(for: account) + self.applicationState.amountOfNewStatuses = await HomeTimelineService.shared.amountOfNewStatuses(for: account, + includeReblogs: self.applicationState.showReboostedStatuses) } } } diff --git a/Vernissage/Views/HomeFeedView.swift b/Vernissage/Views/HomeFeedView.swift index b79623d..8d8be89 100644 --- a/Vernissage/Views/HomeFeedView.swift +++ b/Vernissage/Views/HomeFeedView.swift @@ -69,7 +69,7 @@ struct HomeFeedView: View { .task { do { if let account = self.applicationState.account { - let newStatusesCount = try await HomeTimelineService.shared.loadOnBottom(for: account) + let newStatusesCount = try await HomeTimelineService.shared.loadOnBottom(for: account, includeReblogs: self.applicationState.showReboostedStatuses) if newStatusesCount == 0 { allItemsLoaded = true } @@ -101,7 +101,7 @@ struct HomeFeedView: View { private func refreshData() async { do { if let account = self.applicationState.account { - let lastSeenStatusId = try await HomeTimelineService.shared.refreshTimeline(for: account, updateLastSeenStatus: true) + let lastSeenStatusId = try await HomeTimelineService.shared.refreshTimeline(for: account, includeReblogs: self.applicationState.showReboostedStatuses, updateLastSeenStatus: true) asyncAfter(0.35) { self.applicationState.lastSeenStatusId = lastSeenStatusId @@ -125,7 +125,7 @@ struct HomeFeedView: View { } if let account = self.applicationState.account { - _ = try await HomeTimelineService.shared.refreshTimeline(for: account) + _ = try await HomeTimelineService.shared.refreshTimeline(for: account, includeReblogs: self.applicationState.showReboostedStatuses) } self.applicationState.amountOfNewStatuses = 0 diff --git a/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift b/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift index ffdd5e9..8fb41dc 100644 --- a/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift +++ b/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift @@ -85,6 +85,18 @@ struct MediaSettingsView: View { .onChange(of: self.applicationState.warnAboutMissingAlt) { newValue in ApplicationSettingsHandler.shared.set(warnAboutMissingAlt: newValue) } + + Toggle(isOn: $applicationState.showReboostedStatuses) { + VStack(alignment: .leading) { + Text("settings.title.enableReboostOnTimeline", comment: "Show boosted statuses") + Text("settings.title.enableReboostOnTimelineDescription", comment: "Boosted statuses will be visible on your home timeline.") + .font(.footnote) + .foregroundColor(.customGrayColor) + } + } + .onChange(of: self.applicationState.showReboostedStatuses) { newValue in + ApplicationSettingsHandler.shared.set(showReboostedStatuses: newValue) + } } } } diff --git a/Vernissage/Views/StatusesView.swift b/Vernissage/Views/StatusesView.swift index 590f27c..4abc9ef 100644 --- a/Vernissage/Views/StatusesView.swift +++ b/Vernissage/Views/StatusesView.swift @@ -239,7 +239,8 @@ struct StatusesView: View { maxId: maxId, sinceId: sinceId, minId: minId, - limit: self.defaultLimit) ?? [] + limit: self.defaultLimit, + includeReblogs: self.applicationState.showReboostedStatuses) ?? [] case .local: return try await self.client.publicTimeline?.getStatuses( local: true, diff --git a/Vernissage/Widgets/ImageRowItem.swift b/Vernissage/Widgets/ImageRowItem.swift index af57c70..e34952e 100644 --- a/Vernissage/Widgets/ImageRowItem.swift +++ b/Vernissage/Widgets/ImageRowItem.swift @@ -61,7 +61,10 @@ struct ImageRowItem: View { } blurred: { ZStack { BlurredImage(blurhash: attachmentData.blurhash) - ImageAvatar(displayName: self.status.accountDisplayName, avatarUrl: self.status.accountAvatar) { + ImageAvatar(displayName: self.status.accountDisplayName, + avatarUrl: self.status.accountAvatar, + rebloggedAccountDisplayName: self.status.rebloggedAccountDisplayName, + rebloggedAccountAvatar: self.status.rebloggedAccountAvatar) { self.routerPath.navigate(to: .userProfile(accountId: self.status.accountId, accountDisplayName: self.status.accountDisplayName, accountUserName: self.status.accountUsername)) @@ -141,7 +144,10 @@ struct ImageRowItem: View { ZStack { self.imageView(uiImage: uiImage) - ImageAvatar(displayName: self.status.accountDisplayName, avatarUrl: self.status.accountAvatar) { + ImageAvatar(displayName: self.status.accountDisplayName, + avatarUrl: self.status.accountAvatar, + rebloggedAccountDisplayName: self.status.rebloggedAccountDisplayName, + rebloggedAccountAvatar: self.status.rebloggedAccountAvatar) { self.routerPath.navigate(to: .userProfile(accountId: self.status.accountId, accountDisplayName: self.status.accountDisplayName, accountUserName: self.status.accountUsername)) @@ -155,6 +161,23 @@ struct ImageRowItem: View { FavouriteTouch(showFavouriteAnimation: $showThumbImage) } } + + @ViewBuilder + func reblogInformation() -> some View { + if let rebloggedAccountAvatar = self.status.rebloggedAccountAvatar, + let rebloggedAccountDisplayName = self.status.rebloggedAccountDisplayName { + HStack(alignment: .center, spacing: 4) { + UserAvatar(accountAvatar: rebloggedAccountAvatar, size: .mini) + Text(rebloggedAccountDisplayName) + Image("custom.rocket") + .padding(.trailing, 8) + } + .font(.footnote) + .foregroundColor(Color.mainTextColor.opacity(0.4)) + .background(Color.mainTextColor.opacity(0.1)) + .clipShape(Capsule()) + } + } @ViewBuilder private func imageView(uiImage: UIImage) -> some View { @@ -228,7 +251,7 @@ struct ImageRowItem: View { private func navigateToStatus() { self.routerPath.navigate(to: .status( - id: status.rebloggedStatusId ?? status.id, + id: status.id, blurhash: status.attachments().first?.blurhash, highestImageUrl: status.attachments().getHighestImage()?.url, metaImageWidth: status.attachments().first?.metaImageWidth, diff --git a/Vernissage/Widgets/ImageRowItemAsync.swift b/Vernissage/Widgets/ImageRowItemAsync.swift index 9d33dd8..2195852 100644 --- a/Vernissage/Widgets/ImageRowItemAsync.swift +++ b/Vernissage/Widgets/ImageRowItemAsync.swift @@ -67,7 +67,9 @@ struct ImageRowItemAsync: View { BlurredImage(blurhash: attachment.blurhash) if self.showAvatar { ImageAvatar(displayName: self.statusViewModel.account.displayNameWithoutEmojis, - avatarUrl: self.statusViewModel.account.avatar) { + avatarUrl: self.statusViewModel.account.avatar, + rebloggedAccountDisplayName: self.statusViewModel.reblogStatus?.account.displayNameWithoutEmojis, + rebloggedAccountAvatar: self.statusViewModel.reblogStatus?.account.avatar) { self.routerPath.navigate(to: .userProfile(accountId: self.statusViewModel.account.id, accountDisplayName: self.statusViewModel.account.displayNameWithoutEmojis, accountUserName: self.statusViewModel.account.acct)) @@ -143,7 +145,9 @@ struct ImageRowItemAsync: View { if self.showAvatar { ImageAvatar(displayName: self.statusViewModel.account.displayNameWithoutEmojis, - avatarUrl: self.statusViewModel.account.avatar) { + avatarUrl: self.statusViewModel.account.avatar, + rebloggedAccountDisplayName: self.statusViewModel.reblogStatus?.account.displayNameWithoutEmojis, + rebloggedAccountAvatar: self.statusViewModel.reblogStatus?.account.avatar) { self.routerPath.navigate(to: .userProfile(accountId: self.statusViewModel.account.id, accountDisplayName: self.statusViewModel.account.displayNameWithoutEmojis, accountUserName: self.statusViewModel.account.acct)) diff --git a/VernissageWidget/PhotoWidget/Service/StatusFetcher.swift b/VernissageWidget/PhotoWidget/Service/StatusFetcher.swift index b42057c..bc12481 100644 --- a/VernissageWidget/PhotoWidget/Service/StatusFetcher.swift +++ b/VernissageWidget/PhotoWidget/Service/StatusFetcher.swift @@ -27,7 +27,7 @@ public class StatusFetcher { } let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken) - let statuses = try await client.getHomeTimeline(limit: 20) + let statuses = try await client.getHomeTimeline(limit: 20, includeReblogs: defaultSettings.showReboostedStatuses) var widgetEntries: [PhotoWidgetEntry] = [] for status in statuses { diff --git a/WidgetsKit/Sources/WidgetsKit/Widgets/ContentWarning.swift b/WidgetsKit/Sources/WidgetsKit/Widgets/ContentWarning.swift index ac5c3ae..182c0ef 100644 --- a/WidgetsKit/Sources/WidgetsKit/Widgets/ContentWarning.swift +++ b/WidgetsKit/Sources/WidgetsKit/Widgets/ContentWarning.swift @@ -29,7 +29,8 @@ public struct ContentWarning: View { .transition(.opacity) VStack(alignment: .trailing) { - HStack(alignment: .top) { + Spacer() + HStack(alignment: .bottom) { Spacer() Button { withAnimation { @@ -40,12 +41,10 @@ public struct ContentWarning: View { .font(.system(size: 18)) .foregroundColor(.white.opacity(0.8)) .shadow(color: Color.black, radius: 1) - .padding(.top, 11) - .padding(.trailing, 16) - .padding([.bottom, .leading], 16) + .padding([.top, .bottom, .leading], 12) } } - Spacer() + .padding(.trailing, 64) } .foregroundColor(.mainTextColor) } diff --git a/WidgetsKit/Sources/WidgetsKit/Widgets/ImageAvatar.swift b/WidgetsKit/Sources/WidgetsKit/Widgets/ImageAvatar.swift index 85e6b26..7e90458 100644 --- a/WidgetsKit/Sources/WidgetsKit/Widgets/ImageAvatar.swift +++ b/WidgetsKit/Sources/WidgetsKit/Widgets/ImageAvatar.swift @@ -14,43 +14,62 @@ public struct ImageAvatar: View { private let displayName: String? private let avatarUrl: URL? + private let rebloggedAccountDisplayName: String? + private let rebloggedAccountAvatar: URL? private let onTap: () -> Void - - public init(displayName: String?, avatarUrl: URL?, onTap: @escaping () -> Void) { + + public init(displayName: String?, avatarUrl: URL?, rebloggedAccountDisplayName: String?, rebloggedAccountAvatar: URL?, onTap: @escaping () -> Void) { self.displayName = displayName self.avatarUrl = avatarUrl + self.rebloggedAccountAvatar = rebloggedAccountAvatar + self.rebloggedAccountDisplayName = rebloggedAccountDisplayName self.onTap = onTap } public var body: some View { if self.applicationState.showAvatarsOnTimeline { - VStack(alignment: .leading) { + VStack(alignment: .leading, spacing: 2) { HStack(alignment: .center) { - HStack(alignment: .center) { - LazyImage(url: avatarUrl) { state in - if let image = state.image { - self.buildAvatar(image: image) - } else if state.isLoading { - self.buildAvatar() - } else { - self.buildAvatar() - } + LazyImage(url: avatarUrl) { state in + if let image = state.image { + self.buildAvatar(image: image) + } else if state.isLoading { + self.buildAvatar() + } else { + self.buildAvatar() } - - Text(displayName ?? "") - .font(.system(size: 15)) - .foregroundColor(.white.opacity(0.8)) - .fontWeight(.semibold) - .shadow(color: .black, radius: 2) - } - .padding(8) - .onTapGesture { - self.onTap() } + Text(displayName ?? "") + .lineLimit(1) + .font(.system(size: 15)) + .foregroundColor(.white.opacity(0.8)) + .fontWeight(.semibold) + .shadow(color: .black, radius: 2) + Spacer() + + if let rebloggedAccountAvatar = self.rebloggedAccountAvatar, + let rebloggedAccountDisplayName = self.rebloggedAccountDisplayName { + HStack(alignment: .center, spacing: 4) { + UserAvatar(accountAvatar: rebloggedAccountAvatar, size: .mini) + Text(rebloggedAccountDisplayName) + .lineLimit(1) + Image("custom.rocket") + .padding(.trailing, 8) + } + .font(.footnote) + .foregroundColor(.white.opacity(0.8)) + .background(.black.opacity(0.4)) + .clipShape(Capsule()) + .padding(.leading, 32) + } } - + .padding(8) + .onTapGesture { + self.onTap() + } + Spacer() } }