diff --git a/.swiftlint.yml b/.swiftlint.yml index e5b23e6..da64edd 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,6 +1,7 @@ only_rules: - accessibility_trait_for_button - array_init + - blanket_disable_command - block_based_kvo - class_delegate_protocol - closing_brace @@ -21,6 +22,7 @@ only_rules: - control_statement - custom_rules - deployment_target + - direct_return - discarded_notification_center_observer - discouraged_assert - discouraged_direct_init @@ -28,6 +30,7 @@ only_rules: - discouraged_object_literal - discouraged_optional_boolean - discouraged_optional_collection + - duplicate_conditions - duplicate_enum_cases - duplicate_imports - duplicated_key_in_dictionary_literal @@ -53,7 +56,7 @@ only_rules: - implicit_getter - implicit_return - inclusive_language - - inert_defer + - invalid_swiftlint_command - is_disjoint - joined_default_parameter - last_where @@ -132,7 +135,6 @@ only_rules: - unneeded_parentheses_in_closure_argument - unowned_variable_capture - untyped_error_in_catch - - unused_capture_list - unused_closure_parameter - unused_control_flow_label - unused_enumerated @@ -178,7 +180,7 @@ identifier_name: - 'y2' - 'z2' deployment_target: - macOS_deployment_target: '11' + macOS_deployment_target: '12' custom_rules: no_nsrect: regex: '\bNSRect\b' diff --git a/Gifski.xcodeproj/project.pbxproj b/Gifski.xcodeproj/project.pbxproj index 8e20dc5..c5eacb1 100644 --- a/Gifski.xcodeproj/project.pbxproj +++ b/Gifski.xcodeproj/project.pbxproj @@ -326,8 +326,9 @@ E3AE627B1E5CD2F300035A2F /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1400; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = "Sindre Sorhus"; TargetAttributes = { 0E79251A2329BDBE00058B94 = { @@ -808,7 +809,7 @@ repositoryURL = "https://github.com/sindresorhus/Defaults"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 7.1.0; + minimumVersion = 7.2.0; }; }; E3339E982395768F00303839 /* XCRemoteSwiftPackageReference "CircularProgress" */ = { @@ -824,7 +825,7 @@ repositoryURL = "https://github.com/sindresorhus/DockProgress"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 4.0.1; + minimumVersion = 4.1.0; }; }; E3C874A8252CFE5B00AB1099 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { @@ -832,7 +833,7 @@ repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 10.5.0; + minimumVersion = 10.9.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/Gifski.xcodeproj/xcshareddata/xcschemes/Gifski.xcscheme b/Gifski.xcodeproj/xcshareddata/xcschemes/Gifski.xcscheme index 0fae654..bc5275e 100644 --- a/Gifski.xcodeproj/xcshareddata/xcschemes/Gifski.xcscheme +++ b/Gifski.xcodeproj/xcshareddata/xcschemes/Gifski.xcscheme @@ -1,6 +1,6 @@ 640 { @@ -316,10 +316,10 @@ final class EditVideoViewController: NSViewController { return } - let frameRate = self.frameRateSlider.integerValue + let frameRate = frameRateSlider.integerValue Defaults[.outputFPS] = frameRate - self.frameRateLabel.stringValue = "\(frameRate)" - self.estimatedFileSizeModel.updateEstimate() + frameRateLabel.stringValue = "\(frameRate)" + estimatedFileSizeModel.updateEstimate() } qualitySlider.onAction = { [weak self] _ in @@ -327,8 +327,8 @@ final class EditVideoViewController: NSViewController { return } - Defaults[.outputQuality] = self.qualitySlider.doubleValue - self.estimatedFileSizeModel.updateEstimate() + Defaults[.outputQuality] = qualitySlider.doubleValue + estimatedFileSizeModel.updateEstimate() } // We round it so that `29.970` becomes `30` for practical reasons. @@ -416,7 +416,7 @@ final class EditVideoViewController: NSViewController { ) alert.showsSuppressionButton = true - alert.runModal(for: self.view.window) + alert.runModal(for: view.window) if alert.suppressionButton?.state == .on { Defaults[.suppressKeyframeWarning] = true @@ -436,8 +436,8 @@ final class EditVideoViewController: NSViewController { return } - self.resizableDimensions.resize(usingWidth: Double(width)) - self.dimensionsUpdated() + resizableDimensions.resize(usingWidth: Double(width)) + dimensionsUpdated() } heightTextField.onBlur = { [weak self] height in @@ -450,8 +450,8 @@ final class EditVideoViewController: NSViewController { return } - self.resizableDimensions.resize(usingHeight: Double(height)) - self.dimensionsUpdated() + resizableDimensions.resize(usingHeight: Double(height)) + dimensionsUpdated() } updateTextFieldsMinMax() @@ -463,11 +463,11 @@ final class EditVideoViewController: NSViewController { return } - self.loopCountTextField.stringValue = "\(loopCount)" - self.loopCountStepper.intValue = Int32(loopCount) + loopCountTextField.stringValue = "\(loopCount)" + loopCountStepper.intValue = Int32(loopCount) if loopCount > 0 { - self.loopCheckbox.state = .off + loopCheckbox.state = .off } } @@ -477,11 +477,11 @@ final class EditVideoViewController: NSViewController { } let validLoopCount = loopCount.clamped(to: Constants.loopCountRange) - self.loopCountTextField.stringValue = "\(validLoopCount)" - self.loopCountStepper.intValue = Int32(validLoopCount) + loopCountTextField.stringValue = "\(validLoopCount)" + loopCountStepper.intValue = Int32(validLoopCount) if validLoopCount > 0 { - self.loopCheckbox.state = .off + loopCheckbox.state = .off } } @@ -490,11 +490,11 @@ final class EditVideoViewController: NSViewController { return } - if self.loopCheckbox.state == .on { - self.loopCountTextField.stringValue = "0" - self.loopCountStepper.intValue = 0 + if loopCheckbox.state == .on { + loopCountTextField.stringValue = "0" + loopCountStepper.intValue = 0 } else { - self.showConversionCompletedAnimationWarningIfNeeded() + showConversionCompletedAnimationWarningIfNeeded() } } @@ -514,10 +514,10 @@ final class EditVideoViewController: NSViewController { return } - self.modifiedAsset = self.asset?.firstVideoTrack?.extractToNewAssetAndChangeSpeed(to: $0.newValue) - self.playerViewController.currentItem = AVPlayerItem(asset: self.modifiedAsset) - self.estimatedFileSizeModel.updateEstimate() - self.updateFrameRateSlider(isInit: false) + modifiedAsset = asset?.firstVideoTrack?.extractToNewAssetAndChangeSpeed(to: $0.newValue) + playerViewController.currentItem = AVPlayerItem(asset: modifiedAsset) + estimatedFileSizeModel.updateEstimate() + updateFrameRateSlider(isInit: false) } .store(in: &cancellables) @@ -527,7 +527,7 @@ final class EditVideoViewController: NSViewController { return } - self.loopCountTextField.stringValue = "\(self.loopCountStepper.intValue)" + loopCountTextField.stringValue = "\(loopCountStepper.intValue)" } } diff --git a/Gifski/EstimatedFileSize.swift b/Gifski/EstimatedFileSize.swift index 5888130..9f24039 100644 --- a/Gifski/EstimatedFileSize.swift +++ b/Gifski/EstimatedFileSize.swift @@ -50,13 +50,13 @@ final class EstimatedFileSizeModel: ObservableObject { // We add 10% extra because it's better to estimate slightly too much than too little. let fileSize = (Double(data.count) * gifski.sizeMultiplierForEstimation) * 1.1 - self.estimatedFileSize = Int(fileSize).formatted(.byteCount(style: .file)) + estimatedFileSize = Int(fileSize).formatted(.byteCount(style: .file)) case .failure(let error): switch error { case .cancelled: break case .notEnoughFrames: - self.estimatedFileSize = self.estimatedFileSizeNaive + estimatedFileSize = estimatedFileSizeNaive default: Crashlytics.recordNonFatalError(error: error) self.error = error diff --git a/Gifski/ExtendedAttributes.swift b/Gifski/ExtendedAttributes.swift index b9eaa6c..ce83f4b 100644 --- a/Gifski/ExtendedAttributes.swift +++ b/Gifski/ExtendedAttributes.swift @@ -110,7 +110,7 @@ final class ExtendedAttributes { func all() throws -> [String] { try checkIfFileURL() - let list: [String] = try url.withUnsafeFileSystemRepresentation { fileSystemPath in + return try url.withUnsafeFileSystemRepresentation { fileSystemPath in let length = listxattr(fileSystemPath, nil, 0, 0) guard length >= 0 else { @@ -127,14 +127,10 @@ final class ExtendedAttributes { throw System.Errno.fromErrno } - let list = data.split(separator: 0).compactMap { + return data.split(separator: 0).compactMap { String(data: Data($0), encoding: .utf8) } - - return list } - - return list } func debug() { diff --git a/Gifski/GIFGenerator.swift b/Gifski/GIFGenerator.swift index 5c86a9d..6a24766 100644 --- a/Gifski/GIFGenerator.swift +++ b/Gifski/GIFGenerator.swift @@ -46,13 +46,13 @@ final class GIFGenerator { } } - self.gifski = Gifski( + gifski = Gifski( dimensions: conversion.dimensions, quality: conversion.quality, loop: conversion.loop ) - self.gifski?.onProgress = { [weak self] in + gifski?.onProgress = { [weak self] in self?.progress.completedUnitCount += 1 } @@ -123,7 +123,7 @@ final class GIFGenerator { return } - let frameResult = self.processFrame( + let frameResult = processFrame( for: imageResult, at: startTime, frameRate: fps, @@ -135,7 +135,7 @@ final class GIFGenerator { switch frameResult { case .success(let finished): if finished { - guard let gifski = self.gifski else { + guard let gifski else { completionHandler(.failure(.cancelled)) return } diff --git a/Gifski/Gifski.swift b/Gifski/Gifski.swift index 0e6f22f..44a2ea4 100644 --- a/Gifski/Gifski.swift +++ b/Gifski/Gifski.swift @@ -59,7 +59,7 @@ final class Gifski { return 0 } - self.onProgress?() + onProgress?() return self.wrapper == nil ? 0 : 1 } @@ -69,7 +69,7 @@ final class Gifski { return 0 } - self.data.append(bufferPointer, count: bufferLength) + data.append(bufferPointer, count: bufferLength) return 0 } diff --git a/Gifski/TimeRemainingEstimator.swift b/Gifski/TimeRemainingEstimator.swift index eb8e063..5c25f36 100644 --- a/Gifski/TimeRemainingEstimator.swift +++ b/Gifski/TimeRemainingEstimator.swift @@ -27,7 +27,7 @@ final class TimeRemainingEstimator { return } - self.percentComplete = $0 + percentComplete = $0 } isCancelledCancellable = progress?.publisher(for: \.isCancelled) @@ -37,7 +37,7 @@ final class TimeRemainingEstimator { } if $0 { - self.state = .done + state = .done } } } diff --git a/Gifski/TrimmingAVPlayerViewController.swift b/Gifski/TrimmingAVPlayerViewController.swift index 51df7ca..ca74082 100644 --- a/Gifski/TrimmingAVPlayerViewController.swift +++ b/Gifski/TrimmingAVPlayerViewController.swift @@ -98,10 +98,10 @@ final class TrimmingAVPlayerViewController: NSViewController { return } - self.playerView.setupTrimmingObserver() + playerView.setupTrimmingObserver() // This is here as it needs to be refreshed when the current item changes. - self.playerView.observeTrimmedTimeRange { [weak self] timeRange in + playerView.observeTrimmedTimeRange { [weak self] timeRange in self?.timeRange = timeRange self?.timeRangeDidChange?(timeRange) } @@ -127,7 +127,7 @@ final class TrimmingAVPlayerView: AVPlayerView { .sink { [weak self] _ in guard let self, - let item = self.player?.currentItem, + let item = player?.currentItem, let fullRange = item.durationRange, let playbackRange = item.playbackRange else { @@ -137,13 +137,13 @@ final class TrimmingAVPlayerView: AVPlayerView { // Prevent infinite recursion. guard !skipNextUpdate else { skipNextUpdate = false - updateClosure(playbackRange.minimumRangeLength(of: self.minimumTrimDuration, in: fullRange)) + updateClosure(playbackRange.minimumRangeLength(of: minimumTrimDuration, in: fullRange)) return } - guard playbackRange.length > self.minimumTrimDuration else { + guard playbackRange.length > minimumTrimDuration else { skipNextUpdate = true - item.playbackRange = playbackRange.minimumRangeLength(of: self.minimumTrimDuration, in: fullRange) + item.playbackRange = playbackRange.minimumRangeLength(of: minimumTrimDuration, in: fullRange) return } @@ -161,10 +161,10 @@ final class TrimmingAVPlayerView: AVPlayerView { return } - self.beginTrimming(completionHandler: nil) - self.hideTrimButtons() - self.window?.makeFirstResponder(self) - self.trimmingCancellable = nil + beginTrimming(completionHandler: nil) + hideTrimButtons() + window?.makeFirstResponder(self) + trimmingCancellable = nil } } diff --git a/Gifski/VideoValidator.swift b/Gifski/VideoValidator.swift index 38185fa..54307be 100644 --- a/Gifski/VideoValidator.swift +++ b/Gifski/VideoValidator.swift @@ -102,12 +102,10 @@ struct VideoValidator { let codec = firstVideoTrack.codec, codec.isSupported { - NSAlert.showModalAndReportToCrashlytics( + NSAlert.showModal( for: window, title: "The video could not be decoded even though its codec “\(codec)” is supported.", - message: cannotReadVideoExplanation, - showDebugInfo: false, - debugInfo: asset.debugInfo + message: cannotReadVideoExplanation ) return .failure diff --git a/ShareExtension/ShareViewController.swift b/ShareExtension/ShareViewController.swift index 9526eb4..b1c48b4 100644 --- a/ShareExtension/ShareViewController.swift +++ b/ShareExtension/ShareViewController.swift @@ -37,7 +37,7 @@ final class ShareViewController: NSViewController { } guard let url else { - self.presentError(message: error?.localizedDescription ?? "Unknown error") + presentError(message: error?.localizedDescription ?? "Unknown error") return } @@ -46,7 +46,7 @@ final class ShareViewController: NSViewController { guard let appGroupShareVideoUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Shared.videoShareGroupIdentifier)?.appendingPathComponent(shareUrl, isDirectory: false) else { - self.presentError(message: "Could not share the video with the main app.") + presentError(message: "Could not share the video with the main app.") return } @@ -55,18 +55,18 @@ final class ShareViewController: NSViewController { do { try FileManager.default.copyItem(at: url, to: appGroupShareVideoUrl) } catch { - self.presentError(message: error.localizedDescription) + presentError(message: error.localizedDescription) return } guard - let gifski = self.createMainAppUrl( + let gifski = createMainAppUrl( queryItems: [ URLQueryItem(name: "path", value: shareUrl) ] ) else { - self.presentError(message: "Could not share the video with the main app.") + presentError(message: "Could not share the video with the main app.") return } diff --git a/readme.md b/readme.md index 98c57d6..612197e 100644 --- a/readme.md +++ b/readme.md @@ -25,10 +25,10 @@ Requires macOS 12 or later. **Older versions** -- [Last macOS 11 compatible version](https://github.com/sindresorhus/Gifski/releases/download/v2.21.2/Gifski.2.21.2.-.macOS.11.zip) *(2.21.2)* -- [Last macOS 10.15 compatible version](https://github.com/sindresorhus/Gifski/releases/download/v2.20.2/Gifski.2.20.2.-.macOS.10.15.zip) *(2.20.2)* -- [Last macOS 10.14 compatible version](https://github.com/sindresorhus/Gifski/releases/download/v2.16.0/Gifski.2.16.0.-.macOS.10.14.zip) *(2.16.0)* -- [Last macOS 10.13 compatible version](https://github.com/sindresorhus/Gifski/files/3991913/Gifski.2.4.0.-.High.Sierra.zip) *(2.4.0)* +- [2.21.2](https://github.com/sindresorhus/Gifski/releases/download/v2.21.2/Gifski.2.21.2.-.macOS.11.zip) for macOS 11+ +- [2.20.2](https://github.com/sindresorhus/Gifski/releases/download/v2.20.2/Gifski.2.20.2.-.macOS.10.15.zip) for macOS 10.15+ +- [2.16.0](https://github.com/sindresorhus/Gifski/releases/download/v2.16.0/Gifski.2.16.0.-.macOS.10.14.zip) for macOS 10.14+ +- [2.4.0](https://github.com/sindresorhus/Gifski/files/3991913/Gifski.2.4.0.-.High.Sierra.zip) for macOS 10.13+ **Non-App Store version**