Add favourite icon on the timelines
This commit is contained in:
parent
325f142b97
commit
6b8cbec48e
|
@ -23,7 +23,6 @@ public class StatusModel: ObservableObject {
|
||||||
public let favouritesCount: Int
|
public let favouritesCount: Int
|
||||||
public let repliesCount: Int
|
public let repliesCount: Int
|
||||||
public let reblogged: Bool
|
public let reblogged: Bool
|
||||||
public let favourited: Bool
|
|
||||||
public let sensitive: Bool
|
public let sensitive: Bool
|
||||||
public let bookmarked: Bool
|
public let bookmarked: Bool
|
||||||
public let pinned: Bool
|
public let pinned: Bool
|
||||||
|
@ -39,6 +38,7 @@ public class StatusModel: ObservableObject {
|
||||||
|
|
||||||
public let reblogStatus: Status?
|
public let reblogStatus: Status?
|
||||||
|
|
||||||
|
@Published public var favourited: Bool
|
||||||
@Published public var mediaAttachments: [AttachmentModel]
|
@Published public var mediaAttachments: [AttachmentModel]
|
||||||
|
|
||||||
public init(status: Status) {
|
public init(status: Status) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ extension ApplicationSettings {
|
||||||
@NSManaged public var showPhotoDescription: Bool
|
@NSManaged public var showPhotoDescription: Bool
|
||||||
@NSManaged public var menuPosition: Int32
|
@NSManaged public var menuPosition: Int32
|
||||||
@NSManaged public var showAvatarsOnTimeline: Bool
|
@NSManaged public var showAvatarsOnTimeline: Bool
|
||||||
|
@NSManaged public var showFavouritesOnTimeline: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ApplicationSettings: Identifiable {
|
extension ApplicationSettings: Identifiable {
|
||||||
|
|
|
@ -55,6 +55,7 @@ class ApplicationSettingsHandler {
|
||||||
applicationState.showSensitive = defaultSettings.showSensitive
|
applicationState.showSensitive = defaultSettings.showSensitive
|
||||||
applicationState.showPhotoDescription = defaultSettings.showPhotoDescription
|
applicationState.showPhotoDescription = defaultSettings.showPhotoDescription
|
||||||
applicationState.showAvatarsOnTimeline = defaultSettings.showAvatarsOnTimeline
|
applicationState.showAvatarsOnTimeline = defaultSettings.showAvatarsOnTimeline
|
||||||
|
applicationState.showFavouritesOnTimeline = defaultSettings.showFavouritesOnTimeline
|
||||||
|
|
||||||
if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) {
|
if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) {
|
||||||
applicationState.menuPosition = menuPosition
|
applicationState.menuPosition = menuPosition
|
||||||
|
@ -151,6 +152,12 @@ class ApplicationSettingsHandler {
|
||||||
CoreDataHandler.shared.save()
|
CoreDataHandler.shared.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func set(showFavouritesOnTimeline: Bool) {
|
||||||
|
let defaultSettings = self.get()
|
||||||
|
defaultSettings.showFavouritesOnTimeline = showFavouritesOnTimeline
|
||||||
|
CoreDataHandler.shared.save()
|
||||||
|
}
|
||||||
|
|
||||||
private func createApplicationSettingsEntity(viewContext: NSManagedObjectContext? = nil) -> ApplicationSettings {
|
private func createApplicationSettingsEntity(viewContext: NSManagedObjectContext? = nil) -> ApplicationSettings {
|
||||||
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
return ApplicationSettings(context: context)
|
return ApplicationSettings(context: context)
|
||||||
|
|
|
@ -28,8 +28,8 @@ class StatusDataHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStatusData(accountId: String, statusId: String) -> StatusData? {
|
func getStatusData(accountId: String, statusId: String, viewContext: NSManagedObjectContext? = nil) -> StatusData? {
|
||||||
let context = CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
let fetchRequest = StatusData.fetchRequest()
|
let fetchRequest = StatusData.fetchRequest()
|
||||||
|
|
||||||
fetchRequest.fetchLimit = 1
|
fetchRequest.fetchLimit = 1
|
||||||
|
@ -114,6 +114,15 @@ class StatusDataHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setFavourited(accountId: String, statusId: String) {
|
||||||
|
let backgroundContext = CoreDataHandler.shared.newBackgroundContext()
|
||||||
|
|
||||||
|
if let statusData = self.getStatusData(accountId: accountId, statusId: statusId, viewContext: backgroundContext) {
|
||||||
|
statusData.favourited = true
|
||||||
|
CoreDataHandler.shared.save(viewContext: backgroundContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createStatusDataEntity(viewContext: NSManagedObjectContext? = nil) -> StatusData {
|
func createStatusDataEntity(viewContext: NSManagedObjectContext? = nil) -> StatusData {
|
||||||
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
return StatusData(context: context)
|
return StatusData(context: context)
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>_XCCurrentVersionName</key>
|
<key>_XCCurrentVersionName</key>
|
||||||
<string>Vernissage-008.xcdatamodel</string>
|
<string>Vernissage-009.xcdatamodel</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22E261" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
|
<entity name="AccountData" representedClassName="AccountData" syncable="YES">
|
||||||
|
<attribute name="accessToken" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="acct" attributeType="String"/>
|
||||||
|
<attribute name="avatar" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="avatarData" optional="YES" attributeType="Binary"/>
|
||||||
|
<attribute name="clientId" attributeType="String"/>
|
||||||
|
<attribute name="clientSecret" attributeType="String"/>
|
||||||
|
<attribute name="clientVapidKey" attributeType="String"/>
|
||||||
|
<attribute name="createdAt" attributeType="String"/>
|
||||||
|
<attribute name="displayName" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="followersCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="followingCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="header" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="id" attributeType="String"/>
|
||||||
|
<attribute name="lastSeenStatusId" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="locked" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="note" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="refreshToken" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="serverUrl" attributeType="URI"/>
|
||||||
|
<attribute name="statusesCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="username" attributeType="String"/>
|
||||||
|
<relationship name="statuses" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="StatusData" inverseName="pixelfedAccount" inverseEntity="StatusData"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="ApplicationSettings" representedClassName="ApplicationSettings" syncable="YES">
|
||||||
|
<attribute name="activeIcon" attributeType="String" defaultValueString="Default"/>
|
||||||
|
<attribute name="avatarShape" attributeType="Integer 32" defaultValueString="1" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="currentAccount" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="hapticAnimationEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="hapticButtonPressEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="hapticNotificationEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="hapticRefreshEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="hapticTabSelectionEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="lastRefreshTokens" attributeType="Date" defaultDateTimeInterval="694256400" usesScalarValueType="NO"/>
|
||||||
|
<attribute name="menuPosition" attributeType="Integer 32" defaultValueString="1" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="showAvatarsOnTimeline" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="showFavouritesOnTimeline" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="showPhotoDescription" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="showSensitive" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="theme" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="tintColor" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="AttachmentData" representedClassName="AttachmentData" syncable="YES">
|
||||||
|
<attribute name="blurhash" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="data" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES"/>
|
||||||
|
<attribute name="exifCamera" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="exifCreatedDate" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="exifExposure" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="exifLens" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="id" attributeType="String"/>
|
||||||
|
<attribute name="metaImageHeight" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="metaImageWidth" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="previewUrl" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="remoteUrl" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="statusId" attributeType="String"/>
|
||||||
|
<attribute name="text" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="type" attributeType="String"/>
|
||||||
|
<attribute name="url" attributeType="URI"/>
|
||||||
|
<relationship name="statusRelation" maxCount="1" deletionRule="Nullify" destinationEntity="StatusData" inverseName="attachmentsRelation" inverseEntity="StatusData"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="StatusData" representedClassName="StatusData" syncable="YES">
|
||||||
|
<attribute name="accountAvatar" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="accountDisplayName" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="accountId" attributeType="String"/>
|
||||||
|
<attribute name="accountUsername" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="applicationName" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="applicationWebsite" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="bookmarked" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="content" attributeType="String"/>
|
||||||
|
<attribute name="createdAt" attributeType="String"/>
|
||||||
|
<attribute name="favourited" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="favouritesCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="id" attributeType="String"/>
|
||||||
|
<attribute name="inReplyToAccount" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="inReplyToId" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="muted" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="pinned" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="reblogged" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="rebloggedAccountAvatar" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="rebloggedAccountDisplayName" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="rebloggedAccountId" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="rebloggedAccountUsername" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="rebloggedStatusId" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="reblogsCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="repliesCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="sensitive" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="spoilerText" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="uri" attributeType="String"/>
|
||||||
|
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||||
|
<attribute name="visibility" attributeType="String"/>
|
||||||
|
<relationship name="attachmentsRelation" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="AttachmentData" inverseName="statusRelation" inverseEntity="AttachmentData"/>
|
||||||
|
<relationship name="pixelfedAccount" maxCount="1" deletionRule="Nullify" destinationEntity="AccountData" inverseName="statuses" inverseEntity="AccountData"/>
|
||||||
|
</entity>
|
||||||
|
</model>
|
|
@ -92,6 +92,9 @@ public class ApplicationState: ObservableObject {
|
||||||
/// Should avatars be visible on timelines.
|
/// Should avatars be visible on timelines.
|
||||||
@Published public var showAvatarsOnTimeline = false
|
@Published public var showAvatarsOnTimeline = false
|
||||||
|
|
||||||
|
/// Should favourites be visible on timelines.
|
||||||
|
@Published public var showFavouritesOnTimeline = false
|
||||||
|
|
||||||
public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) {
|
public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) {
|
||||||
self.account = accountModel
|
self.account = accountModel
|
||||||
self.lastSeenStatusId = lastSeenStatusId
|
self.lastSeenStatusId = lastSeenStatusId
|
||||||
|
|
|
@ -211,7 +211,10 @@
|
||||||
"settings.title.topMenu" = "Navigation bar";
|
"settings.title.topMenu" = "Navigation bar";
|
||||||
"settings.title.bottomRightMenu" = "Bottom right";
|
"settings.title.bottomRightMenu" = "Bottom right";
|
||||||
"settings.title.bottomLeftMenu" = "Bottom left";
|
"settings.title.bottomLeftMenu" = "Bottom left";
|
||||||
"settings.title.showAvatarsOnTimeline" = "Show avatars on timelines";
|
"settings.title.showAvatars" = "Show avatars";
|
||||||
|
"settings.title.showAvatarsOnTimeline" = "Avatars will be displayed on timelines";
|
||||||
|
"settings.title.showFavourite" = "Show favourites";
|
||||||
|
"settings.title.showFavouriteOnTimeline" = "Favourites will be displayed on timelines";
|
||||||
|
|
||||||
// Mark: Signin view.
|
// Mark: Signin view.
|
||||||
"signin.navigationBar.title" = "Sign in to Pixelfed";
|
"signin.navigationBar.title" = "Sign in to Pixelfed";
|
||||||
|
|
|
@ -211,7 +211,10 @@
|
||||||
"settings.title.topMenu" = "Nabigazio barra";
|
"settings.title.topMenu" = "Nabigazio barra";
|
||||||
"settings.title.bottomRightMenu" = "Behe eskumaldean";
|
"settings.title.bottomRightMenu" = "Behe eskumaldean";
|
||||||
"settings.title.bottomLeftMenu" = "Behe ezkerraldean";
|
"settings.title.bottomLeftMenu" = "Behe ezkerraldean";
|
||||||
"settings.title.showAvatarsOnTimeline" = "Show avatars on timelines";
|
"settings.title.showAvatars" = "Show avatars";
|
||||||
|
"settings.title.showAvatarsOnTimeline" = "Avatars will be displayed on timelines";
|
||||||
|
"settings.title.showFavourite" = "Show favourites";
|
||||||
|
"settings.title.showFavouriteOnTimeline" = "Favourites will be displayed on timelines";
|
||||||
|
|
||||||
// Mark: Signin view.
|
// Mark: Signin view.
|
||||||
"signin.navigationBar.title" = "Hasi saioa Pixelfed-en";
|
"signin.navigationBar.title" = "Hasi saioa Pixelfed-en";
|
||||||
|
|
|
@ -211,7 +211,10 @@
|
||||||
"settings.title.topMenu" = "Panel tytułowy";
|
"settings.title.topMenu" = "Panel tytułowy";
|
||||||
"settings.title.bottomRightMenu" = "Dolny prawy";
|
"settings.title.bottomRightMenu" = "Dolny prawy";
|
||||||
"settings.title.bottomLeftMenu" = "Dolny lewy";
|
"settings.title.bottomLeftMenu" = "Dolny lewy";
|
||||||
"settings.title.showAvatarsOnTimeline" = "Wyświetlaj awatary na osiach zdjęć";
|
"settings.title.showAvatars" = "Wyświetlaj awatary";
|
||||||
|
"settings.title.showAvatarsOnTimeline" = "Awatary będą widoczne na osiach zdjęć";
|
||||||
|
"settings.title.showFavourite" = "Wyświetlaj polubienia";
|
||||||
|
"settings.title.showFavouriteOnTimeline" = "Polubienia będą widoczne na osiach zdjęć";
|
||||||
|
|
||||||
// Mark: Signin view.
|
// Mark: Signin view.
|
||||||
"signin.navigationBar.title" = "Zaloguj się do Pixelfed";
|
"signin.navigationBar.title" = "Zaloguj się do Pixelfed";
|
||||||
|
|
|
@ -176,6 +176,7 @@
|
||||||
F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */; };
|
F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */; };
|
||||||
F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */; };
|
F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */; };
|
||||||
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; };
|
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; };
|
||||||
|
F8FFBD4829E9901E0047EE80 /* ImageFavourite.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FFBD4729E9901E0047EE80 /* ImageFavourite.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -357,6 +358,8 @@
|
||||||
F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumWidgetView.swift; sourceTree = "<group>"; };
|
F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumWidgetView.swift; sourceTree = "<group>"; };
|
||||||
F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeWidgetView.swift; sourceTree = "<group>"; };
|
F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeWidgetView.swift; sourceTree = "<group>"; };
|
||||||
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = "<group>"; };
|
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = "<group>"; };
|
||||||
|
F8FFBD4729E9901E0047EE80 /* ImageFavourite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFavourite.swift; sourceTree = "<group>"; };
|
||||||
|
F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-009.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -636,6 +639,7 @@
|
||||||
children = (
|
children = (
|
||||||
F88BC53A29E06A5100CE6141 /* ImageContextMenu.swift */,
|
F88BC53A29E06A5100CE6141 /* ImageContextMenu.swift */,
|
||||||
F8A4A88229E3FD1C00267E36 /* ImageAvatar.swift */,
|
F8A4A88229E3FD1C00267E36 /* ImageAvatar.swift */,
|
||||||
|
F8FFBD4729E9901E0047EE80 /* ImageFavourite.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModifiers;
|
path = ViewModifiers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1076,6 +1080,7 @@
|
||||||
F86B7221296C49A300EE59EC /* EmptyButtonStyle.swift in Sources */,
|
F86B7221296C49A300EE59EC /* EmptyButtonStyle.swift in Sources */,
|
||||||
F80048042961850500E6868A /* AttachmentData+CoreDataProperties.swift in Sources */,
|
F80048042961850500E6868A /* AttachmentData+CoreDataProperties.swift in Sources */,
|
||||||
F88E4D4A297EA0490057491A /* RouterPath.swift in Sources */,
|
F88E4D4A297EA0490057491A /* RouterPath.swift in Sources */,
|
||||||
|
F8FFBD4829E9901E0047EE80 /* ImageFavourite.swift in Sources */,
|
||||||
F88E4D48297E90CD0057491A /* TrendStatusesView.swift in Sources */,
|
F88E4D48297E90CD0057491A /* TrendStatusesView.swift in Sources */,
|
||||||
F8A4A88329E3FD1C00267E36 /* ImageAvatar.swift in Sources */,
|
F8A4A88329E3FD1C00267E36 /* ImageAvatar.swift in Sources */,
|
||||||
F800480A2961EA1900E6868A /* AttachmentDataHandler.swift in Sources */,
|
F800480A2961EA1900E6868A /* AttachmentDataHandler.swift in Sources */,
|
||||||
|
@ -1612,6 +1617,7 @@
|
||||||
F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */ = {
|
F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */ = {
|
||||||
isa = XCVersionGroup;
|
isa = XCVersionGroup;
|
||||||
children = (
|
children = (
|
||||||
|
F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */,
|
||||||
F8A4A88429E4099900267E36 /* Vernissage-008.xcdatamodel */,
|
F8A4A88429E4099900267E36 /* Vernissage-008.xcdatamodel */,
|
||||||
F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */,
|
F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */,
|
||||||
F8EF371429C624DA00669F45 /* Vernissage-006.xcdatamodel */,
|
F8EF371429C624DA00669F45 /* Vernissage-006.xcdatamodel */,
|
||||||
|
@ -1622,7 +1628,7 @@
|
||||||
F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */,
|
F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */,
|
||||||
F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */,
|
F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */,
|
||||||
);
|
);
|
||||||
currentVersion = F8A4A88429E4099900267E36 /* Vernissage-008.xcdatamodel */;
|
currentVersion = F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */;
|
||||||
path = Vernissage.xcdatamodeld;
|
path = Vernissage.xcdatamodeld;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
versionGroupType = wrapper.xcdatamodel;
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// https://mczachurski.dev
|
||||||
|
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||||
|
// Licensed under the Apache License 2.0.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
import NukeUI
|
||||||
|
import ClientKit
|
||||||
|
import ServicesKit
|
||||||
|
import EnvironmentKit
|
||||||
|
|
||||||
|
public extension View {
|
||||||
|
func imageFavourite(isFavourited: Binding<Bool>) -> some View {
|
||||||
|
modifier(ImageFavourite(isFavourited: isFavourited))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ImageFavourite: ViewModifier {
|
||||||
|
@EnvironmentObject var applicationState: ApplicationState
|
||||||
|
@Binding private var isFavourited: Bool
|
||||||
|
|
||||||
|
init(isFavourited: Binding<Bool>) {
|
||||||
|
self._isFavourited = isFavourited
|
||||||
|
}
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if self.applicationState.showFavouritesOnTimeline && self.isFavourited {
|
||||||
|
ZStack {
|
||||||
|
// Image.
|
||||||
|
content
|
||||||
|
|
||||||
|
// Avatar.
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Image(systemName: "star.fill")
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.shadow(color: .black, radius: 4)
|
||||||
|
.foregroundColor(.white.opacity(0.8))
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.leading, 12)
|
||||||
|
.padding(.bottom, 14)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,10 +84,29 @@ struct GeneralSectionView: View {
|
||||||
ApplicationSettingsHandler.shared.set(menuPosition: menuPosition)
|
ApplicationSettingsHandler.shared.set(menuPosition: menuPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle("settings.title.showAvatarsOnTimeline", isOn: $applicationState.showAvatarsOnTimeline)
|
Toggle(isOn: $applicationState.showAvatarsOnTimeline) {
|
||||||
.onChange(of: self.applicationState.showAvatarsOnTimeline) { newValue in
|
VStack(alignment: .leading) {
|
||||||
ApplicationSettingsHandler.shared.set(showAvatarsOnTimeline: newValue)
|
Text("settings.title.showAvatars", comment: "Show avatars")
|
||||||
|
Text("settings.title.showAvatarsOnTimeline", comment: "Show avatars on timeline")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.lightGrayColor)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: self.applicationState.showAvatarsOnTimeline) { newValue in
|
||||||
|
ApplicationSettingsHandler.shared.set(showAvatarsOnTimeline: newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $applicationState.showFavouritesOnTimeline) {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("settings.title.showFavourite", comment: "Show favourites")
|
||||||
|
Text("settings.title.showFavouriteOnTimeline", comment: "Show favourites on timeline")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.lightGrayColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: self.applicationState.showFavouritesOnTimeline) { newValue in
|
||||||
|
ApplicationSettingsHandler.shared.set(showFavouritesOnTimeline: newValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct ImageRowItem: View {
|
||||||
@State private var cancelled = true
|
@State private var cancelled = true
|
||||||
@State private var error: Error?
|
@State private var error: Error?
|
||||||
@State private var opacity = 0.0
|
@State private var opacity = 0.0
|
||||||
|
@State private var isFavourited = false
|
||||||
|
|
||||||
private let onImageDownloaded: (Double, Double) -> Void
|
private let onImageDownloaded: (Double, Double) -> Void
|
||||||
|
|
||||||
|
@ -114,18 +115,32 @@ struct ImageRowItem: View {
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.onTapGesture(count: 2) {
|
.onTapGesture(count: 2) {
|
||||||
Task {
|
Task {
|
||||||
try? await self.client.statuses?.favourite(statusId: self.status.id)
|
// Update favourite in Pixelfed server.
|
||||||
|
_ = try? await self.client.statuses?.favourite(statusId: self.status.id)
|
||||||
|
|
||||||
|
// Update favourite in local cache (core data).
|
||||||
|
if let accountId = self.applicationState.account?.id {
|
||||||
|
StatusDataHandler.shared.setFavourited(accountId: accountId, statusId: self.status.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run adnimation and haptic feedback.
|
||||||
self.showThumbImage = true
|
self.showThumbImage = true
|
||||||
HapticService.shared.fireHaptic(of: .buttonPress)
|
HapticService.shared.fireHaptic(of: .buttonPress)
|
||||||
|
|
||||||
|
// Mark favourite booleans used to show star in the timeline view.
|
||||||
|
self.isFavourited = true
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
self.navigateToStatus()
|
self.navigateToStatus()
|
||||||
}
|
}
|
||||||
.imageAvatar(displayName: self.status.accountDisplayName,
|
.imageAvatar(displayName: self.status.accountDisplayName,
|
||||||
avatarUrl: self.status.accountAvatar)
|
avatarUrl: self.status.accountAvatar)
|
||||||
|
.imageFavourite(isFavourited: $isFavourited)
|
||||||
.imageContextMenu(statusData: self.status)
|
.imageContextMenu(statusData: self.status)
|
||||||
|
.onAppear {
|
||||||
|
self.isFavourited = self.status.favourited
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func downloadImage(attachmentData: AttachmentData) async {
|
private func downloadImage(attachmentData: AttachmentData) async {
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct ImageRowItemAsync: View {
|
||||||
|
|
||||||
@State private var showThumbImage = false
|
@State private var showThumbImage = false
|
||||||
@State private var opacity = 0.0
|
@State private var opacity = 0.0
|
||||||
|
@State private var isFavourited = false
|
||||||
|
|
||||||
private let onImageDownloaded: (Double, Double) -> Void
|
private let onImageDownloaded: (Double, Double) -> Void
|
||||||
|
|
||||||
|
@ -122,11 +123,17 @@ struct ImageRowItemAsync: View {
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.onTapGesture(count: 2) {
|
.onTapGesture(count: 2) {
|
||||||
Task {
|
Task {
|
||||||
|
// Update favourite in Pixelfed server.
|
||||||
try? await self.client.statuses?.favourite(statusId: self.statusViewModel.id)
|
try? await self.client.statuses?.favourite(statusId: self.statusViewModel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run adnimation and haptic feedback.
|
||||||
self.showThumbImage = true
|
self.showThumbImage = true
|
||||||
HapticService.shared.fireHaptic(of: .buttonPress)
|
HapticService.shared.fireHaptic(of: .buttonPress)
|
||||||
|
|
||||||
|
// Mark favourite booleans used to show star in the timeline view.
|
||||||
|
self.statusViewModel.favourited = true
|
||||||
|
self.isFavourited = true
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
self.navigateToStatus()
|
self.navigateToStatus()
|
||||||
|
@ -135,7 +142,11 @@ struct ImageRowItemAsync: View {
|
||||||
$0.imageAvatar(displayName: self.statusViewModel.account.displayNameWithoutEmojis,
|
$0.imageAvatar(displayName: self.statusViewModel.account.displayNameWithoutEmojis,
|
||||||
avatarUrl: self.statusViewModel.account.avatar)
|
avatarUrl: self.statusViewModel.account.avatar)
|
||||||
}
|
}
|
||||||
|
.imageFavourite(isFavourited: $isFavourited)
|
||||||
.imageContextMenu(statusModel: self.statusViewModel)
|
.imageContextMenu(statusModel: self.statusViewModel)
|
||||||
|
.onAppear {
|
||||||
|
self.isFavourited = self.statusViewModel.favourited
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func navigateToStatus() {
|
private func navigateToStatus() {
|
||||||
|
|
Loading…
Reference in New Issue