Improve path settings, add icons
This commit is contained in:
@@ -105,6 +105,7 @@
|
|||||||
E25DA59B2D024A2B00AEF16D /* DateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25DA59A2D024A2900AEF16D /* DateItem.swift */; };
|
E25DA59B2D024A2B00AEF16D /* DateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25DA59A2D024A2900AEF16D /* DateItem.swift */; };
|
||||||
E26C300F2E634B3A00FEB26D /* TimeInterval+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26C300E2E634B3A00FEB26D /* TimeInterval+Extensions.swift */; };
|
E26C300F2E634B3A00FEB26D /* TimeInterval+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26C300E2E634B3A00FEB26D /* TimeInterval+Extensions.swift */; };
|
||||||
E2720B882DF38BB700FDB543 /* Insert+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2720B872DF38BB200FDB543 /* Insert+Video.swift */; };
|
E2720B882DF38BB700FDB543 /* Insert+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2720B872DF38BB200FDB543 /* Insert+Video.swift */; };
|
||||||
|
E29A577E2E9E444800B19DA3 /* ToolSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29A577D2E9E444000B19DA3 /* ToolSettings.swift */; };
|
||||||
E29D31202D0320E70051B7F4 /* ContentLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D311F2D0320E20051B7F4 /* ContentLabels.swift */; };
|
E29D31202D0320E70051B7F4 /* ContentLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D311F2D0320E20051B7F4 /* ContentLabels.swift */; };
|
||||||
E29D31222D0363FD0051B7F4 /* ContentButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D31212D0363FA0051B7F4 /* ContentButtons.swift */; };
|
E29D31222D0363FD0051B7F4 /* ContentButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D31212D0363FA0051B7F4 /* ContentButtons.swift */; };
|
||||||
E29D31242D0366860051B7F4 /* TagList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D31232D0366820051B7F4 /* TagList.swift */; };
|
E29D31242D0366860051B7F4 /* TagList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29D31232D0366820051B7F4 /* TagList.swift */; };
|
||||||
@@ -415,6 +416,7 @@
|
|||||||
E25DA59A2D024A2900AEF16D /* DateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateItem.swift; sourceTree = "<group>"; };
|
E25DA59A2D024A2900AEF16D /* DateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateItem.swift; sourceTree = "<group>"; };
|
||||||
E26C300E2E634B3A00FEB26D /* TimeInterval+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Extensions.swift"; sourceTree = "<group>"; };
|
E26C300E2E634B3A00FEB26D /* TimeInterval+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
E2720B872DF38BB200FDB543 /* Insert+Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Insert+Video.swift"; sourceTree = "<group>"; };
|
E2720B872DF38BB200FDB543 /* Insert+Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Insert+Video.swift"; sourceTree = "<group>"; };
|
||||||
|
E29A577D2E9E444000B19DA3 /* ToolSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolSettings.swift; sourceTree = "<group>"; };
|
||||||
E29D311F2D0320E20051B7F4 /* ContentLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLabels.swift; sourceTree = "<group>"; };
|
E29D311F2D0320E20051B7F4 /* ContentLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLabels.swift; sourceTree = "<group>"; };
|
||||||
E29D31212D0363FA0051B7F4 /* ContentButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentButtons.swift; sourceTree = "<group>"; };
|
E29D31212D0363FA0051B7F4 /* ContentButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentButtons.swift; sourceTree = "<group>"; };
|
||||||
E29D31232D0366820051B7F4 /* TagList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagList.swift; sourceTree = "<group>"; };
|
E29D31232D0366820051B7F4 /* TagList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagList.swift; sourceTree = "<group>"; };
|
||||||
@@ -781,6 +783,7 @@
|
|||||||
E25DA53B2D0042EA00AEF16D /* Settings */ = {
|
E25DA53B2D0042EA00AEF16D /* Settings */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E29A577D2E9E444000B19DA3 /* ToolSettings.swift */,
|
||||||
E2FD1D2D2D37180600B48627 /* GeneralSettings.swift */,
|
E2FD1D2D2D37180600B48627 /* GeneralSettings.swift */,
|
||||||
E2FE0F392D2B3E4E002963B7 /* AudioPlayerSettings.swift */,
|
E2FE0F392D2B3E4E002963B7 /* AudioPlayerSettings.swift */,
|
||||||
E2FE0F6D2D2D3685002963B7 /* LocalizedAudioPlayerSettings.swift */,
|
E2FE0F6D2D2D3685002963B7 /* LocalizedAudioPlayerSettings.swift */,
|
||||||
@@ -1389,7 +1392,7 @@
|
|||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1540;
|
LastSwiftUpdateCheck = 1540;
|
||||||
LastUpgradeCheck = 1630;
|
LastUpgradeCheck = 2600;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
E2DD046F2C276F31003BFF1F = {
|
E2DD046F2C276F31003BFF1F = {
|
||||||
CreatedOnToolsVersion = 15.4;
|
CreatedOnToolsVersion = 15.4;
|
||||||
@@ -1663,6 +1666,7 @@
|
|||||||
E2F3B3982DC54F9400CFA712 /* ChangeObservingItem.swift in Sources */,
|
E2F3B3982DC54F9400CFA712 /* ChangeObservingItem.swift in Sources */,
|
||||||
E21850372CFCA55F0090B18B /* LocalizedPostSettings.swift in Sources */,
|
E21850372CFCA55F0090B18B /* LocalizedPostSettings.swift in Sources */,
|
||||||
E2FD1D642D47EF4200B48627 /* DetailListItem.swift in Sources */,
|
E2FD1D642D47EF4200B48627 /* DetailListItem.swift in Sources */,
|
||||||
|
E29A577E2E9E444800B19DA3 /* ToolSettings.swift in Sources */,
|
||||||
E2FE0F0B2D2689FF002963B7 /* FeedGeneratorSource.swift in Sources */,
|
E2FE0F0B2D2689FF002963B7 /* FeedGeneratorSource.swift in Sources */,
|
||||||
E2DD04742C276F31003BFF1F /* MainView.swift in Sources */,
|
E2DD04742C276F31003BFF1F /* MainView.swift in Sources */,
|
||||||
E20BCCAD2D53F48100B8DBEB /* IssueStatus.swift in Sources */,
|
E20BCCAD2D53F48100B8DBEB /* IssueStatus.swift in Sources */,
|
||||||
@@ -1811,6 +1815,7 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
};
|
};
|
||||||
@@ -1867,6 +1872,7 @@
|
|||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
@@ -1899,7 +1905,7 @@
|
|||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||||
MARKETING_VERSION = 1.5;
|
MARKETING_VERSION = 1.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = de.christophhagen.CHDataManagement;
|
PRODUCT_BUNDLE_IDENTIFIER = de.christophhagen.CHDataManagement;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
@@ -1938,7 +1944,7 @@
|
|||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||||
MARKETING_VERSION = 1.5;
|
MARKETING_VERSION = 1.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = de.christophhagen.CHDataManagement;
|
PRODUCT_BUNDLE_IDENTIFIER = de.christophhagen.CHDataManagement;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "6a373ae0a2cc4ad97293e2b13e76aa783451436d6a17beb2295cd5e9b2067122",
|
"originHash" : "f8a1ac1b6fd2d65b9edf0e288c06780ac6a71414f18592b869bb082fb8c7690d",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "async-http-client",
|
"identity" : "async-http-client",
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/christophhagen/BinaryCodable",
|
"location" : "https://github.com/christophhagen/BinaryCodable",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "4febea33ee5d813fd9c94c9158be6c85472480d2",
|
"revision" : "53f057050f3c78a1997ed0218337fd92d2eba2b5",
|
||||||
"version" : "3.1.0"
|
"version" : "3.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1630"
|
LastUpgradeVersion = "2600"
|
||||||
version = "1.7">
|
version = "1.7">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import _math
|
|
||||||
|
|
||||||
extension Double {
|
extension Double {
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ extension Double {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rounded(decimals: Int) -> Double {
|
func rounded(decimals: Int) -> Double {
|
||||||
let factor = _math.pow(10.0, Double(decimals))
|
let factor = Double.pow(10.0, Double(decimals))
|
||||||
return (self * factor).rounded() / factor
|
return (self * factor).rounded() / factor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,8 +188,7 @@ final class ImageGenerator {
|
|||||||
|
|
||||||
// TODO: Run in security scope
|
// TODO: Run in security scope
|
||||||
let process = Process()
|
let process = Process()
|
||||||
#warning("TODO: Move avifenc path to settings")
|
process.launchPath = settings.tools.avifencPath
|
||||||
process.launchPath = "/opt/homebrew/bin/avifenc" // Adjust based on installation
|
|
||||||
process.arguments = ["-q", "\(quality)", imagePath, generatedImagePath]
|
process.arguments = ["-q", "\(quality)", imagePath, generatedImagePath]
|
||||||
|
|
||||||
let pipe = Pipe()
|
let pipe = Pipe()
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ extension ContentLanguage: Comparable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ContentLanguage: CustomStringConvertible {
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension ContentLanguage {
|
extension ContentLanguage {
|
||||||
|
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ final class FileResource: Item, LocalizedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func determineVideoType() -> String? {
|
private func determineVideoType() -> String? {
|
||||||
#warning("TODO: Move ffmpeg path to settings")
|
let ffmpegPath = content.settings.tools.ffprobePath
|
||||||
switch type {
|
switch type {
|
||||||
case .webm:
|
case .webm:
|
||||||
return "video/webm"
|
return "video/webm"
|
||||||
@@ -371,7 +371,7 @@ final class FileResource: Item, LocalizedItem {
|
|||||||
let process = Process()
|
let process = Process()
|
||||||
let arguments = "-v error -select_streams v:0 -show_entries stream=codec_tag_string -of default=noprint_wrappers=1:nokey=1 \(path.path())"
|
let arguments = "-v error -select_streams v:0 -show_entries stream=codec_tag_string -of default=noprint_wrappers=1:nokey=1 \(path.path())"
|
||||||
.components(separatedBy: " ")
|
.components(separatedBy: " ")
|
||||||
process.launchPath = "/opt/homebrew/bin/ffprobe"
|
process.launchPath = ffmpegPath
|
||||||
process.arguments = Array(arguments)
|
process.arguments = Array(arguments)
|
||||||
|
|
||||||
let pipe = Pipe()
|
let pipe = Pipe()
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ final class Settings: ChangeObservableItem {
|
|||||||
@Published
|
@Published
|
||||||
var audioPlayer: AudioPlayerSettings
|
var audioPlayer: AudioPlayerSettings
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var tools: ToolSettings
|
||||||
|
|
||||||
weak var content: Content?
|
weak var content: Content?
|
||||||
|
|
||||||
var cancellables: Set<AnyCancellable> = []
|
var cancellables: Set<AnyCancellable> = []
|
||||||
@@ -31,13 +34,15 @@ final class Settings: ChangeObservableItem {
|
|||||||
navigation: NavigationSettings,
|
navigation: NavigationSettings,
|
||||||
posts: PostSettings,
|
posts: PostSettings,
|
||||||
pages: PageSettings,
|
pages: PageSettings,
|
||||||
audioPlayer: AudioPlayerSettings) {
|
audioPlayer: AudioPlayerSettings,
|
||||||
|
tools: ToolSettings) {
|
||||||
self.general = general
|
self.general = general
|
||||||
self.paths = paths
|
self.paths = paths
|
||||||
self.navigation = navigation
|
self.navigation = navigation
|
||||||
self.posts = posts
|
self.posts = posts
|
||||||
self.pages = pages
|
self.pages = pages
|
||||||
self.audioPlayer = audioPlayer
|
self.audioPlayer = audioPlayer
|
||||||
|
self.tools = tools
|
||||||
observeChildChanges()
|
observeChildChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +63,7 @@ final class Settings: ChangeObservableItem {
|
|||||||
observe(posts)
|
observe(posts)
|
||||||
observe(pages)
|
observe(pages)
|
||||||
observe(audioPlayer)
|
observe(audioPlayer)
|
||||||
|
observe(tools)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +78,8 @@ extension Settings {
|
|||||||
navigation: .init(context: context, data: data.navigation),
|
navigation: .init(context: context, data: data.navigation),
|
||||||
posts: .init(context: context, data: data.posts),
|
posts: .init(context: context, data: data.posts),
|
||||||
pages: .init(context: context, data: data.pages),
|
pages: .init(context: context, data: data.pages),
|
||||||
audioPlayer: .init(context: context, data: data.audioPlayer))
|
audioPlayer: .init(context: context, data: data.audioPlayer),
|
||||||
|
tools: .init(context: context, data: data.tools))
|
||||||
content = context.content
|
content = context.content
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +91,8 @@ extension Settings {
|
|||||||
posts: posts.data,
|
posts: posts.data,
|
||||||
pages: pages.data,
|
pages: pages.data,
|
||||||
audioPlayer: audioPlayer.data,
|
audioPlayer: audioPlayer.data,
|
||||||
tagOverview: tagOverview?.data)
|
tagOverview: tagOverview?.data,
|
||||||
|
tools: tools.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Data: Codable, Equatable {
|
struct Data: Codable, Equatable {
|
||||||
@@ -95,6 +103,7 @@ extension Settings {
|
|||||||
let pages: PageSettings.Data
|
let pages: PageSettings.Data
|
||||||
let audioPlayer: AudioPlayerSettings.Data
|
let audioPlayer: AudioPlayerSettings.Data
|
||||||
let tagOverview: Tag.Data?
|
let tagOverview: Tag.Data?
|
||||||
|
let tools: ToolSettings.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveToDisk(_ data: Data) -> Bool {
|
func saveToDisk(_ data: Data) -> Bool {
|
||||||
@@ -110,7 +119,8 @@ extension Settings {
|
|||||||
navigation: .default,
|
navigation: .default,
|
||||||
posts: .default,
|
posts: .default,
|
||||||
pages: .default,
|
pages: .default,
|
||||||
audioPlayer: .default)
|
audioPlayer: .default,
|
||||||
|
tools: .default)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension GeneralSettings {
|
extension GeneralSettings {
|
||||||
@@ -195,3 +205,11 @@ extension PageSettings {
|
|||||||
emptyPageText: "This page is empty"))
|
emptyPageText: "This page is empty"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ToolSettings {
|
||||||
|
|
||||||
|
static var `default`: ToolSettings {
|
||||||
|
.init(ffprobePath: "/opt/homebrew/bin/ffprobe",
|
||||||
|
avifencPath: "/opt/homebrew/bin/avifenc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
39
CHDataManagement/Model/Settings/ToolSettings.swift
Normal file
39
CHDataManagement/Model/Settings/ToolSettings.swift
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class ToolSettings: ObservableObject {
|
||||||
|
|
||||||
|
/// The items to show in the navigation bar
|
||||||
|
@Published
|
||||||
|
var ffprobePath: String
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var avifencPath: String
|
||||||
|
|
||||||
|
init(ffprobePath: String,
|
||||||
|
avifencPath: String) {
|
||||||
|
self.ffprobePath = ffprobePath
|
||||||
|
self.avifencPath = avifencPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Storage
|
||||||
|
|
||||||
|
extension ToolSettings {
|
||||||
|
|
||||||
|
convenience init(context: LoadingContext, data: ToolSettings.Data) {
|
||||||
|
self.init(
|
||||||
|
ffprobePath: data.ffprobePath,
|
||||||
|
avifencPath: data.avifencPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Data: Codable, Equatable {
|
||||||
|
let ffprobePath: String
|
||||||
|
let avifencPath: String
|
||||||
|
}
|
||||||
|
|
||||||
|
var data: Data {
|
||||||
|
.init(
|
||||||
|
ffprobePath: ffprobePath,
|
||||||
|
avifencPath: avifencPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -133,3 +133,33 @@ extension Icon {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Icon {
|
||||||
|
|
||||||
|
struct Pencil: ContentIcon {
|
||||||
|
|
||||||
|
static let id = "icon-pencil"
|
||||||
|
|
||||||
|
static let attributes = "viewBox='0 0 16 16' fill='currentColor'"
|
||||||
|
|
||||||
|
static let content =
|
||||||
|
"""
|
||||||
|
<path d="M12.9.1a.5.5 0 0 0-.8 0l-1.6 1.7 3.7 3.7L16 3.9a.5.5 0 0 0 0-.8zm.6 6.1L9.8 2.5 3.3 9h.2a1 1 0 0 1 .5.5v.5h.5a1 1 0 0 1 .5.5v.5h.5a1 1 0 0 1 .5.5v.5h.5a1 1 0 0 1 .5.5v.2zM6 13.7V13h-.5a1 1 0 0 1-.5-.5V12h-.5a1 1 0 0 1-.5-.5V11h-.5a1 1 0 0 1-.5-.5V10h-.7l-.2.1v.2l-2 5a.5.5 0 0 0 .6.7l5-2 .2-.1z"/>
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Icon {
|
||||||
|
|
||||||
|
struct PersonPlus: ContentIcon {
|
||||||
|
|
||||||
|
static let id = "person-plus"
|
||||||
|
|
||||||
|
static let attributes = "viewBox='0 0 16 16' fill='currentColor'"
|
||||||
|
|
||||||
|
static let content =
|
||||||
|
"""
|
||||||
|
<path d="M12.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7m.5-5v1h1a.5.5 0 0 1 0 1h-1v1a.5.5 0 0 1-1 0v-1h-1a.5.5 0 0 1 0-1h1v-1a.5.5 0 0 1 1 0m-2-6a3 3 0 1 1-6 0 3 3 0 0 1 6 0M8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4"/><path d="M8.3 14 8 13H3q0-.5.8-1.7c.7-.6 2-1.3 4.2-1.3h.7l.8-.9L8 9c-5 0-6 3-6 4s1 1 1 1z"/>
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ enum PageIcon: String, CaseIterable {
|
|||||||
|
|
||||||
case bellSlash = "bell-slash"
|
case bellSlash = "bell-slash"
|
||||||
|
|
||||||
|
case pencil
|
||||||
|
|
||||||
|
case personPlus = "person-plus"
|
||||||
|
|
||||||
// MARK: Statistics
|
// MARK: Statistics
|
||||||
|
|
||||||
case statisticsTime = "time"
|
case statisticsTime = "time"
|
||||||
@@ -97,6 +101,8 @@ enum PageIcon: String, CaseIterable {
|
|||||||
case .leftRightArrow: Icon.LeftRightArrow.self
|
case .leftRightArrow: Icon.LeftRightArrow.self
|
||||||
case .bell: Icon.Bell.self
|
case .bell: Icon.Bell.self
|
||||||
case .bellSlash: Icon.BellSlash.self
|
case .bellSlash: Icon.BellSlash.self
|
||||||
|
case .pencil: Icon.Pencil.self
|
||||||
|
case .personPlus: Icon.PersonPlus.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +117,8 @@ enum PageIcon: String, CaseIterable {
|
|||||||
case .video: "Video"
|
case .video: "Video"
|
||||||
case .bell: "Bell"
|
case .bell: "Bell"
|
||||||
case .bellSlash: "Bell With Slash"
|
case .bellSlash: "Bell With Slash"
|
||||||
|
case .pencil: "Pencil"
|
||||||
|
case .personPlus: "Person Plus"
|
||||||
case .leftRightArrow: "LeftRightArrow"
|
case .leftRightArrow: "LeftRightArrow"
|
||||||
case .buttonExternalLink: "Button: External Link"
|
case .buttonExternalLink: "Button: External Link"
|
||||||
case .buttonGitLink: "Button: Git Link"
|
case .buttonGitLink: "Button: Git Link"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import SFSafeSymbols
|
import SFSafeSymbols
|
||||||
import SwiftUICore
|
import SwiftUI
|
||||||
|
|
||||||
enum SaveState {
|
enum SaveState {
|
||||||
case storageNotInitialized
|
case storageNotInitialized
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ struct SecurityBookmark {
|
|||||||
with(relativePath: relativeSource) { source in
|
with(relativePath: relativeSource) { source in
|
||||||
if !exists(source) {
|
if !exists(source) {
|
||||||
if !failIfMissing { return true }
|
if !failIfMissing { return true }
|
||||||
reportError("Failed to move \(relativeSource): File does not exist")
|
reportError("Failed to move \(relativeSource): File \(source) does not exist")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ struct GenerationContentView: View {
|
|||||||
statusWhenNonEmpty: .warning,
|
statusWhenNonEmpty: .warning,
|
||||||
items: $content.results.emptyPages) { pageId in
|
items: $content.results.emptyPages) { pageId in
|
||||||
HStack {
|
HStack {
|
||||||
Text("\(pageId.pageId) (\(pageId.language))")
|
Text("\(pageId.pageId) (\(pageId.language.description))")
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("Show") {
|
Button("Show") {
|
||||||
show(page: pageId.pageId,
|
show(page: pageId.pageId,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import SFSafeSymbols
|
import SFSafeSymbols
|
||||||
import SwiftUICore
|
import SwiftUI
|
||||||
|
|
||||||
enum IssueStatus {
|
enum IssueStatus {
|
||||||
case nominal
|
case nominal
|
||||||
|
|||||||
Reference in New Issue
Block a user