Add new settings.

This commit is contained in:
Marcin Czachursk 2023-03-05 09:53:06 +01:00
parent c5e177463e
commit de260b8758
13 changed files with 372 additions and 14 deletions

View File

@ -133,6 +133,8 @@
F8AD061329A565620042F111 /* String+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AD061229A565620042F111 /* String+Random.swift */; };
F8AFF7C129B259150087D083 /* TrendingTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C029B259150087D083 /* TrendingTagsView.swift */; };
F8AFF7C429B25EF40087D083 /* TagImagesGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C329B25EF40087D083 /* TagImagesGridView.swift */; };
F8B05ACB29B489B100857221 /* HapticsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B05ACA29B489B100857221 /* HapticsSectionView.swift */; };
F8B05ACE29B48E2F00857221 /* MediaSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B05ACD29B48E2F00857221 /* MediaSettingsView.swift */; };
F8B0885E29942E31002AB40A /* ThirdPartyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B0885D29942E31002AB40A /* ThirdPartyView.swift */; };
F8B0886029943498002AB40A /* OtherSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B0885F29943498002AB40A /* OtherSectionView.swift */; };
F8B08862299435C9002AB40A /* SupportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B08861299435C9002AB40A /* SupportView.swift */; };
@ -287,6 +289,10 @@
F8AD061229A565620042F111 /* String+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Random.swift"; sourceTree = "<group>"; };
F8AFF7C029B259150087D083 /* TrendingTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingTagsView.swift; sourceTree = "<group>"; };
F8AFF7C329B25EF40087D083 /* TagImagesGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagImagesGridView.swift; sourceTree = "<group>"; };
F8B05AC929B488C600857221 /* Vernissage-003.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-003.xcdatamodel"; sourceTree = "<group>"; };
F8B05ACA29B489B100857221 /* HapticsSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticsSectionView.swift; sourceTree = "<group>"; };
F8B05ACC29B48DD000857221 /* Vernissage-004.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-004.xcdatamodel"; sourceTree = "<group>"; };
F8B05ACD29B48E2F00857221 /* MediaSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaSettingsView.swift; sourceTree = "<group>"; };
F8B0885D29942E31002AB40A /* ThirdPartyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartyView.swift; sourceTree = "<group>"; };
F8B0885F29943498002AB40A /* OtherSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherSectionView.swift; sourceTree = "<group>"; };
F8B08861299435C9002AB40A /* SupportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportView.swift; sourceTree = "<group>"; };
@ -509,6 +515,8 @@
F8B0885F29943498002AB40A /* OtherSectionView.swift */,
F8B08861299435C9002AB40A /* SupportView.swift */,
F86A4306299AA5E900DF7645 /* ThanksView.swift */,
F8B05ACA29B489B100857221 /* HapticsSectionView.swift */,
F8B05ACD29B48E2F00857221 /* MediaSettingsView.swift */,
);
path = Subviews;
sourceTree = "<group>";
@ -864,6 +872,7 @@
F897978A2968314A00B22335 /* LoadingIndicator.swift in Sources */,
F8B9B351298D4B34009CC69C /* Client+Account.swift in Sources */,
F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */,
F8B05ACB29B489B100857221 /* HapticsSectionView.swift in Sources */,
F88FAD2B295F43B8009B20C9 /* AccountData+CoreDataProperties.swift in Sources */,
F85D4975296407F100751DF7 /* HomeTimelineService.swift in Sources */,
F80048062961850500E6868A /* StatusData+CoreDataProperties.swift in Sources */,
@ -887,6 +896,7 @@
F8B9B353298D4B5D009CC69C /* Client+Search.swift in Sources */,
F85D497B29640C8200751DF7 /* UsernameRow.swift in Sources */,
F86A4305299AA12800DF7645 /* PurchaseError.swift in Sources */,
F8B05ACE29B48E2F00857221 /* MediaSettingsView.swift in Sources */,
F89D6C4429718092001DA3D4 /* AccentsSectionView.swift in Sources */,
F88E4D42297E69FD0057491A /* StatusesView.swift in Sources */,
F86FB555298BF83F000131F0 /* FavouriteTouch.swift in Sources */,
@ -1115,7 +1125,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 48;
CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
@ -1152,7 +1162,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 48;
CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
@ -1281,11 +1291,13 @@
F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
F8B05ACC29B48DD000857221 /* Vernissage-004.xcdatamodel */,
F8B05AC929B488C600857221 /* Vernissage-003.xcdatamodel */,
F89F0605299139F6003DC875 /* Vernissage-002.xcdatamodel */,
F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */,
F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */,
);
currentVersion = F89F0605299139F6003DC875 /* Vernissage-002.xcdatamodel */;
currentVersion = F8B05ACC29B48DD000857221 /* Vernissage-004.xcdatamodel */;
path = Vernissage.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;

View File

@ -18,6 +18,14 @@ extension ApplicationSettings {
@NSManaged public var tintColor: Int32
@NSManaged public var avatarShape: Int32
@NSManaged public var lastRefreshTokens: Date
@NSManaged public var hapticTabSelectionEnabled: Bool
@NSManaged public var hapticRefreshEnabled: Bool
@NSManaged public var hapticButtonPressEnabled: Bool
@NSManaged public var hapticAnimationEnabled: Bool
@NSManaged public var hapticNotificationEnabled: Bool
@NSManaged public var showSensitive: Bool
}
extension ApplicationSettings : Identifiable {

View File

@ -62,4 +62,40 @@ class ApplicationSettingsHandler {
let context = CoreDataHandler.shared.container.viewContext
return ApplicationSettings(context: context)
}
func setHapticTabSelectionEnabled(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.hapticTabSelectionEnabled = value
CoreDataHandler.shared.save()
}
func setHapticRefreshEnabled(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.hapticRefreshEnabled = value
CoreDataHandler.shared.save()
}
func setHapticAnimationEnabled(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.hapticAnimationEnabled = value
CoreDataHandler.shared.save()
}
func setHapticNotificationEnabled(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.hapticNotificationEnabled = value
CoreDataHandler.shared.save()
}
func setHapticButtonPressEnabled(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.hapticButtonPressEnabled = value
CoreDataHandler.shared.save()
}
func setShowSensitive(value: Bool) {
let defaultSettings = self.getDefaultSettings()
defaultSettings.showSensitive = value
CoreDataHandler.shared.save()
}
}

View File

@ -55,6 +55,24 @@ public class ApplicationState: ObservableObject {
/// Status id for showed interaction row.
@Published var showInteractionStatusId = String.empty()
/// Should we fire haptic when user change tabs.
@Published var hapticTabSelectionEnabled = true
/// Should we fire haptic when user refresh list.
@Published var hapticRefreshEnabled = true
/// Should we fire haptic when user tap button.
@Published var hapticButtonPressEnabled = true
/// Should we fire haptic when animation is finished.
@Published var hapticAnimationEnabled = true
/// Should we fire haptic when notification occures.
@Published var hapticNotificationEnabled = true
/// Should sensitive photos without mask.
@Published var showSensitive = false
public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) {
self.account = accountModel
self.lastSeenStatusId = lastSeenStatusId

View File

@ -15,7 +15,6 @@ public class HapticService {
case dataRefresh(intensity: CGFloat)
case notification(_ type: UINotificationFeedbackGenerator.FeedbackType)
case tabSelection
case timeline
case animation
}
@ -34,17 +33,25 @@ public class HapticService {
switch type {
case .buttonPress:
impactGenerator.impactOccurred()
if ApplicationState.shared.hapticButtonPressEnabled {
impactGenerator.impactOccurred()
}
case let .dataRefresh(intensity):
impactGenerator.impactOccurred(intensity: intensity)
if ApplicationState.shared.hapticRefreshEnabled {
impactGenerator.impactOccurred(intensity: intensity)
}
case let .notification(type):
notificationGenerator.notificationOccurred(type)
if ApplicationState.shared.hapticNotificationEnabled {
notificationGenerator.notificationOccurred(type)
}
case .tabSelection:
selectionGenerator.selectionChanged()
case .timeline:
selectionGenerator.selectionChanged()
if ApplicationState.shared.hapticTabSelectionEnabled {
selectionGenerator.selectionChanged()
}
case .animation:
selectionGenerator.selectionChanged()
if ApplicationState.shared.hapticAnimationEnabled {
selectionGenerator.selectionChanged()
}
}
}

View File

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>Vernissage-002.xcdatamodel</string>
<string>Vernissage-004.xcdatamodel</string>
</dict>
</plist>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" 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="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="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>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" 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="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="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>

View File

@ -34,6 +34,12 @@ struct SettingsView: View {
// Avatar shapes.
AvatarShapesSectionView()
// Media settings view.
MediaSettingsView()
// Haptics.
HapticsSectionView()
// Support.
SupportView()

View File

@ -0,0 +1,61 @@
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
// Licensed under the MIT License.
//
import SwiftUI
struct HapticsSectionView: View {
@EnvironmentObject var applicationState: ApplicationState
@Environment(\.colorScheme) var colorScheme
@State var hapticTabSelectionEnabled = true
@State var hapticButtonPressEnabled = true
@State var hapticRefreshEnabled = true
@State var hapticAnimationEnabled = true
@State var hapticNotificationEnabled = true
var body: some View {
Section("Haptics") {
Toggle("Tab selection", isOn: $hapticTabSelectionEnabled)
.onChange(of: hapticTabSelectionEnabled) { newValue in
self.applicationState.hapticTabSelectionEnabled = newValue
ApplicationSettingsHandler.shared.setHapticTabSelectionEnabled(value: newValue)
}
Toggle("Button press", isOn: $hapticButtonPressEnabled)
.onChange(of: hapticButtonPressEnabled) { newValue in
self.applicationState.hapticButtonPressEnabled = newValue
ApplicationSettingsHandler.shared.setHapticButtonPressEnabled(value: newValue)
}
Toggle("List refresh", isOn: $hapticRefreshEnabled)
.onChange(of: hapticRefreshEnabled) { newValue in
self.applicationState.hapticRefreshEnabled = newValue
ApplicationSettingsHandler.shared.setHapticRefreshEnabled(value: newValue)
}
Toggle("Animation finished", isOn: $hapticAnimationEnabled)
.onChange(of: hapticAnimationEnabled) { newValue in
self.applicationState.hapticAnimationEnabled = newValue
ApplicationSettingsHandler.shared.setHapticAnimationEnabled(value: newValue)
}
// Toggle("Notification", isOn: $hapticNotificationEnabled)
// .onChange(of: hapticNotificationEnabled) { newValue in
// self.applicationState.hapticNotificationEnabled = newValue
// ApplicationSettingsHandler.shared.setHapticNotificationEnabled(value: newValue)
// }
}
.onAppear {
let defaultSettings = ApplicationSettingsHandler.shared.getDefaultSettings()
self.hapticTabSelectionEnabled = defaultSettings.hapticTabSelectionEnabled
self.hapticButtonPressEnabled = defaultSettings.hapticButtonPressEnabled
self.hapticRefreshEnabled = defaultSettings.hapticRefreshEnabled
self.hapticAnimationEnabled = defaultSettings.hapticAnimationEnabled
self.hapticNotificationEnabled = defaultSettings.hapticNotificationEnabled
}
}
}

View File

@ -0,0 +1,29 @@
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
// Licensed under the MIT License.
//
import SwiftUI
struct MediaSettingsView: View {
@EnvironmentObject var applicationState: ApplicationState
@Environment(\.colorScheme) var colorScheme
@State var showSensitive = true
var body: some View {
Section("Media settings") {
Toggle("Always show NSFW (sensitive)", isOn: $showSensitive)
.onChange(of: showSensitive) { newValue in
self.applicationState.showSensitive = newValue
ApplicationSettingsHandler.shared.setShowSensitive(value: newValue)
}
}
.onAppear {
let defaultSettings = ApplicationSettingsHandler.shared.getDefaultSettings()
self.showSensitive = defaultSettings.showSensitive
}
}
}

View File

@ -46,7 +46,7 @@ struct ImageRow: View {
if let attachmentData {
if let uiImage {
ZStack {
if self.status.sensitive {
if self.status.sensitive && !self.applicationState.showSensitive {
ContentWarning(blurhash: attachmentData.blurhash, spoilerText: self.status.spoilerText) {
Image(uiImage: uiImage)
.resizable()

View File

@ -51,7 +51,7 @@ struct ImageRowAsync: View {
ZStack {
LazyImage(url: attachment.url) { state in
if let image = state.image {
if self.statusViewModel.sensitive {
if self.statusViewModel.sensitive && !self.applicationState.showSensitive {
ZStack {
ContentWarning(blurhash: attachment.blurhash, spoilerText: self.statusViewModel.spoilerText) {
self.imageView(image: image)