diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 5a5e2b2..a8351b1 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -12,12 +12,12 @@ on:
jobs:
macOS-build:
- runs-on: macos-15
+ runs-on: macos-latest
steps:
- name: Checkout the code
uses: actions/checkout@v4
- - name: Select Xcode 16.2
- run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
+# - name: Select Xcode 16.2
+# run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
- uses: mxcl/xcodebuild@v3
with:
platform: macOS
@@ -28,12 +28,12 @@ jobs:
upload-logs: always
macOS-test:
- runs-on: macos-15
+ runs-on: macos-latest
steps:
- name: Checkout the code
uses: actions/checkout@v4
- - name: Select Xcode 16.2
- run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
+# - name: Select Xcode 16.2
+# run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
- uses: mxcl/xcodebuild@v3
with:
platform: macOS
@@ -44,12 +44,12 @@ jobs:
upload-logs: always
iOS-build:
- runs-on: macos-15
+ runs-on: macos-latest
steps:
- name: Checkout the code
uses: actions/checkout@v4
- - name: Select Xcode 16.2
- run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
+# - name: Select Xcode 16.2
+# run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
- uses: mxcl/xcodebuild@v3
with:
platform: iOS
@@ -60,12 +60,12 @@ jobs:
upload-logs: always
iOS-test:
- runs-on: macos-15
+ runs-on: macos-latest
steps:
- name: Checkout the code
uses: actions/checkout@v4
- - name: Select Xcode 16.2
- run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
+# - name: Select Xcode 16.2
+# run: sudo xcode-select -s "/Applications/Xcode_16.2.app"
- uses: mxcl/xcodebuild@v3
with:
platform: iOS
diff --git a/APPROBATION.md b/APPROBATION.md
index eb3dc39..3c7db99 100644
--- a/APPROBATION.md
+++ b/APPROBATION.md
@@ -1,4 +1,4 @@
-# Approbation Matrix / PerseusDarkMode 2.0.0 && 2.0.1 && 2.0.2 && 2.0.3 && 2.0.4
+# Approbation Matrix / PerseusDarkMode 2.0.0 && 2.0.1 && 2.0.2 && 2.0.3 && 2.0.4 && 2.1.0
> NOTE: To catch all log messages Mac Console should be started first then after a little while the logged app.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb497a8..83176a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Dates in this file meets Gregorian calendar. Date in format YYYY-MM-DD.
+## [2.1.0] - [2025-10-30], PerseusDarkMode
+
+### Added
+
+- Contents section to README.
+
+### Updated
+
+- CPL dependency to v1.6.0.
+
## [2.0.4] - [2025-07-22], PerseusDarkMode
### Changed
diff --git a/LICENSE b/LICENSE
index ae281d0..27130df 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
MIT License
-Copyright © 7530 - 7533 Mikhail A. Zhigulin of Novosibirsk
-Copyright © 7533 PerseusRealDeal
+Copyright © 7530 - 7534 Mikhail A. Zhigulin of Novosibirsk
+Copyright © 7533 - 7534 PerseusRealDeal
The year starts from the creation of the world according to a Slavic calendar.
September, the 1st of Slavic year.
diff --git a/PDMStar.swift b/PDMStar.swift
index fd31910..0ba552d 100644
--- a/PDMStar.swift
+++ b/PDMStar.swift
@@ -1,26 +1,26 @@
//
// PDMStar.swift
-// Version: 2.0.4
+// Version: 2.1.0
//
// Standalone PerseusDarkMode.
//
//
// For iOS and macOS only. Use Stars to adopt for the specifics you need.
//
-// DESC: THE DARKNESS YOU CAN FORCE.
+// DESC: THE DARKNESS YOU CAN FORCE
//
// Created by Mikhail Zhigulin in 7530.
//
-// Copyright © 7530 - 7533 Mikhail Zhigulin of Novosibirsk
-// Copyright © 7533 PerseusRealDeal
+// Copyright © 7530 - 7534 Mikhail Zhigulin of Novosibirsk
+// Copyright © 7533 - 7534 PerseusRealDeal
//
// All rights reserved.
//
//
// MIT License
//
-// Copyright © 7530 - 7533 Mikhail A. Zhigulin of Novosibirsk
-// Copyright © 7533 PerseusRealDeal
+// Copyright © 7530 - 7534 Mikhail A. Zhigulin of Novosibirsk
+// Copyright © 7533 - 7534 PerseusRealDeal
//
// The year starts from the creation of the world according to a Slavic calendar.
// September, the 1st of Slavic year.
diff --git a/PDMSupportingStar.swift b/PDMSupportingStar.swift
index 8cb4d68..11ec0e7 100644
--- a/PDMSupportingStar.swift
+++ b/PDMSupportingStar.swift
@@ -1,6 +1,6 @@
//
// PDMSupportingStar.swift
-// Version: 2.0.4
+// Version: 2.1.0
//
// The Darkness Support (PerseusUISystemKit previously)
//
diff --git a/Package.swift b/Package.swift
index 0eecd8e..a66cb4a 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,14 +1,14 @@
// swift-tools-version:5.7
/* Package.swift
- Version: 2.0.4
+ Version: 2.1.0
For iOS and macOS only. Use Stars to adopt for the specifics you need.
Created by Mikhail Zhigulin in 7530.
- Copyright © 7530 - 7533 Mikhail A. Zhigulin of Novosibirsk
- Copyright © 7533 PerseusRealDeal
+ Copyright © 7530 - 7534 Mikhail A. Zhigulin of Novosibirsk
+ Copyright © 7533 - 7534 PerseusRealDeal
Licensed under the MIT license. See LICENSE file.
All rights reserved.
diff --git a/README.md b/README.md
index 1b2395e..66c0337 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,75 @@
# PerseusDarkMode — Xcode 14.2+
-> [`iOS approbation app`](https://github.com/perseusrealdeal/TheOneRing) [`macOS approbation app`](https://github.com/perseusrealdeal/Arkenstone)
-
-> The light-weight darkness in Swift you can force. Hereinafter PDM stands for `P`erseus `D`ark `M`ode.
-
-> - To build option kinda `Night/Day/System Mode` or `On/Off/System Dark Mode`.
-> - To be awared of Dark Mode changes if you need.
-
-> `PDM` is a single author and personale solution developed in `person-to-person` relationship paradigm.
-
[](https://github.com/perseusrealdeal/PerseusDarkMode/actions/workflows/main.yml)
[](https://github.com/perseusrealdeal/PerseusDarkMode/actions/workflows/swiftlint.yml)
-[](/CHANGELOG.md)
-[](https://en.wikipedia.org/wiki/List_of_Apple_products)
+[](/CHANGELOG.md)
+[](https://en.wikipedia.org/wiki/List_of_Apple_products)
[](https://en.wikipedia.org/wiki/Xcode)
[](https://www.swift.org)
[](/LICENSE)
+> Home-made product. The light-weight darkness in Swift you can force.
+
+> `1:` Build option kinda `Night/Day/System Mode` or `On/Off/System Dark Mode`.
+> `2:` Be awared of Dark Mode changes if you need.
+
+> `PDM` is a single author and personale solution developed in `P2P` relationship paradigm.
+
## Integration Capabilities
[](/PDMStar.swift)
[](/Package.swift)
-> Use Stars to adopt [`PDM`](/PDMStar.swift) for the specifics you need.
-
## Dependencies
-[](https://github.com/perseusrealdeal/ConsolePerseusLogger.git)
+[](https://github.com/perseusrealdeal/ConsolePerseusLogger.git)
-# Support Code
+## Support Code
[](/PDMSupportingStar.swift)
[](http://unlicense.org/)
-> [`PDMSupportingStar.swift`](/PDMSupportingStar.swift) is a peace of code a widly helpful in accord with PDM.
+> [`PDMSupportingStar.swift`](/PDMSupportingStar.swift) is a peace of code a widly helpful in accord with PDM.
+> `PDMSupportingStar.swift` goes as an external part of PDM.
+
+## Our Terms
+
+> [`CPL`](https://github.com/perseusrealdeal/ConsolePerseusLogger.git) stands for `C`onsole `P`erseus `L`ogger.
+> [`PGK`](https://github.com/perseusrealdeal/PerseusGeoKit.git) stands for `P`erseus `G`eo `K`it.
+> [`PDM`](https://github.com/perseusrealdeal/PerseusDarkMode.git) stands for `P`erseus `D`ark `M`ode.
+> `P2P` stands for `P`erson-`to`-`P`erson.
+> [`A3`](https://docs.google.com/document/d/1K2jOeIknKRRpTEEIPKhxO2H_1eBTof5uTXxyOm5g6nQ) stands for `A`pple `A`pps `A`pprobation.
+> [`T3`](https://github.com/perseusrealdeal/TheTechnologicalTree) stands for `T`he `T`echnological `T`ree.
+
+## PDM in Use
+
+> `In approbation:` [`iOS app`](https://github.com/perseusrealdeal/TheOneRing) [`macOS app`](https://github.com/perseusrealdeal/Arkenstone)
+> `In business:` [`The Dark Moon`](https://github.com/perseusrealdeal/TheDarkMoon)
-> PDMSupportingStar.swift goes as an external part of PDM.
+> `For details:` [`Approbation and A3 Environment`](/APPROBATION.md) / [`CHANGELOG`](/CHANGELOG.md)
-## Approbation Matrix
+# Contents
-> [`A3 Environment and Approbation`](/APPROBATION.md) / [`CHANGELOG`](/CHANGELOG.md) for details.
+* [In brief](#In-brief)
+* [Build requirements](#Build-requirements)
+* [First-party software](#First-party-software)
+* [Third-party software](#Third-party-software)
+* [Installation](#Installation)
+ * [Cocoa macOS project](#Cocoa-macOS-project)
+ * [UIKit iOS project](#UIKit-iOS-project)
+* [Usage](#Usage)
+ * [Force Dark Mode](#Force-Dark-Mode)
+ * [Get awared of DarkMode changes](#Get-awared-of-DarkMode-changes)
+ * [DarkMode change sample](#DarkMode-change-sample)
+* [Points taken into account](#Points-taken-into-account)
+* [License MIT](#License-MIT)
+ * [Other Required License Notices](#Other-Required-License-Notices)
+* [Credits](#Credits)
+* [Author](#Author)
-## In brief > Idea to use, the Why
+# In brief
-> THE DARKNESS YOU CAN FORCE.
+> THE DARKNESS YOU CAN FORCE
@@ -64,7 +90,7 @@
> [!IMPORTANT]
> Screenshots taken from Approbation Apps [`iOS`](https://github.com/perseusrealdeal/TheOneRing) and [`macOS`](https://github.com/perseusrealdeal/Arkenstone).
-## Build requirements
+# Build requirements
- [macOS Monterey 12.7.6+](https://apps.apple.com/by/app/macos-monterey/id1576738294) / [Xcode 14.2+](https://developer.apple.com/services-account/download?path=/Developer_Tools/Xcode_14.2/Xcode_14.2.xip)
@@ -74,7 +100,7 @@
| Type | Name | License |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
-| Star | [ConsolePerseusLogger](https://github.com/perseusrealdeal/ConsolePerseusLogger) / [1.5.1](https://github.com/perseusrealdeal/ConsolePerseusLogger/releases/tag/1.5.1) | MIT |
+| Star | [ConsolePerseusLogger](https://github.com/perseusrealdeal/ConsolePerseusLogger) / [1.6.0](https://github.com/perseusrealdeal/ConsolePerseusLogger/releases/tag/1.6.0) | MIT |
# Third-party software
@@ -93,7 +119,7 @@
> Swift Package Manager: `https://github.com/perseusrealdeal/PerseusDarkMode`
-## Steps for Cocoa macOS project
+## Cocoa macOS project
`Step 2:` In the AppDelegate when `applicationDidFinishLaunching` call `force`
@@ -139,7 +165,7 @@ class MainWindowController: NSWindowController, NSWindowDelegate {
```
-## Steps for UIKit iOS project
+## UIKit iOS project
`Step 2:` In the AppDelegate when `didFinishLaunchingWithOptions` call `force`
@@ -231,11 +257,11 @@ DarkModeAgent.force(.off) // It's a sunny day for the app.
The `force` will change the appearance of your app immediately including system components and will make run all custom DarkMode code `makeUp()`.
-## Get awared of DarkMode Changes
+## Get awared of DarkMode changes
-> To declare custom DarkMode sensitive code that runs every time if DarkMode Changes register the object or creat a DarkMode trigger:
+> To declare custom DarkMode sensitive code that runs every time if DarkMode Changes register the object or create a DarkMode trigger:
-`Use Case -` Register an object to be notified on changes
+`Use Case 1:` Register an object to be notified on changes
```swift
@@ -252,7 +278,7 @@ class DarkModeSensitiveObject {
```
-`Use Case -` Creat a DarkMode trigger and give it an action
+`Use Case 2:` Create a DarkMode trigger and give it an action
```swift
@@ -273,9 +299,9 @@ class DarkModeSensitiveObject {
```
-## React to DarkMode Changes
+## DarkMode change sample
-`Use Case -` Custom DarkMode Sensitive Color
+`Use Case:` Custom DarkMode sensitive color
```swift
@@ -309,11 +335,12 @@ extension Color {
```
-> Use Custom DarkMode sensitive color.
+> And use custom DarkMode sensitive color:
```swift
-// Runs every time if the DarkMode changes. Use KVO (DarkModeObserver) or be registered by DarkModeAgent.
+// Runs every time if the DarkMode changes.
+// Use KVO (DarkModeObserver) or be registered with DarkModeAgent.
@objc private func makeUp() {
self.backgroundColor = .customRed
}
@@ -330,8 +357,8 @@ extension Color {
# License MIT
-Copyright © 7530 - 7533 Mikhail A. Zhigulin of Novosibirsk
-Copyright © 7533 PerseusRealDeal
+Copyright © 7530 - 7534 Mikhail A. Zhigulin of Novosibirsk
+Copyright © 7533 - 7534 PerseusRealDeal
- The year starts from the creation of the world according to a Slavic calendar.
- September, the 1st of Slavic year. It means that "Sep 01, 2024" is the beginning of 7533.
diff --git a/Sources/PerseusDarkMode/CPLStar.swift b/Sources/PerseusDarkMode/CPLStar.swift
index c8bf903..9bb6c61 100644
--- a/Sources/PerseusDarkMode/CPLStar.swift
+++ b/Sources/PerseusDarkMode/CPLStar.swift
@@ -1,11 +1,10 @@
//
// CPLStar.swift
-// Version: 1.5.1
+// Version: 1.6.0
//
// Standalone ConsolePerseusLogger.
//
-//
-// For iOS and macOS only. Use Stars to adopt for the specifics you need.
+// For iOS and macOS. Use Stars to adopt for the specifics you need.
//
// DESC: USE LOGGER LIKE A VARIABLE ANYWHERE YOU WANT.
//
@@ -13,16 +12,19 @@
//
// Created by Mikhail Zhigulin in 7531.
//
-// Copyright © 7531 - 7533 Mikhail A. Zhigulin of Novosibirsk
-// Copyright © 7531 - 7533 PerseusRealDeal
+// BASED_ON_LOGGER: https://gist.github.com/PerseusRealDeal/df456a9825fcface44eca738056eb6d5
+// BASED_ON_REPORT: https://gist.github.com/PerseusRealDeal/9a4118301b59d43969d8edf5ebc3a571
+//
+// Copyright © 7531 - 7534 Mikhail A. Zhigulin of Novosibirsk
+// Copyright © 7531 - 7534 PerseusRealDeal
//
// All rights reserved.
//
//
// MIT License
//
-// Copyright © 7531 - 7533 Mikhail A. Zhigulin of Novosibirsk
-// Copyright © 7531 - 7533 PerseusRealDeal
+// Copyright © 7531 - 7534 Mikhail A. Zhigulin of Novosibirsk
+// Copyright © 7531 - 7534 PerseusRealDeal
//
// The year starts from the creation of the world according to a Slavic calendar.
// September, the 1st of Slavic year.
@@ -52,19 +54,27 @@ import Foundation
import os
// swiftlint:disable type_name
-typealias log = PerseusLogger // In SPM package should be not public except TheOne.
+typealias log = PerseusLogger // Not public in SPM package, except TheOne.
// swiftlint:enable type_name
-public typealias ConsoleObject = (subsystem: String, category: String)
-public typealias LocalTime = (date: String, time: String)
-public typealias PIDandTID = (pid: String, tid: String) // PID and Thread ID.
-
-public typealias MessageDelegate = (
- (String, PerseusLogger.Level, LocalTime, PIDandTID) -> Void
-)
+// Not public in SPM package, except TheOne.
+protocol PerseusDelegatedMessage: AnyObject {
+ var message: String { get set }
+}
public class PerseusLogger {
+ // MARK: - Typealiases
+
+ public typealias ConsoleObject = (subsystem: String, category: String)
+ public typealias LocalTime = (date: String, time: String, timeUTC: TimeInterval)
+ public typealias PIDandTID = (pid: String, tid: String) // PID and Thread ID.
+ public typealias Directives = (fileName: String, line: UInt) // #file and #line.
+
+ public typealias MessageDelegate = (
+ (String, Level, LocalTime, PIDandTID, User, Directives) -> Void
+ )
+
// MARK: - Constants
private static let SUBSYSTEM = "Perseus"
@@ -72,18 +82,24 @@ public class PerseusLogger {
// MARK: - Specifics
- public enum Status: String, Decodable {
+ public enum Status: String, Decodable, CaseIterable {
case on
case off
}
- public enum Output: String, Decodable {
+ public enum Output: String, Decodable, CaseIterable {
case standard // In Use: Swift.print("").
- case consoleapp
- case custom // In Use: customActionOnMessage?(_:_:_:_:).
+ case consoleapp // In Use: Logger structure from iOS 14.0, macOS 11.0, NSLog otherwise.
+ case custom // In Use: customActionOnMessage?(_:_:_:_:_:_:).
+ }
+
+ // log.message("Notification...", .notice, .custom, .enduser)
+ public enum User: String, Decodable, CaseIterable {
+ case enduser // Ignores status turned == .off; level == .notice is recommended.
+ case operative
}
- public enum Level: Int, CustomStringConvertible, Decodable {
+ public enum Level: Int, CustomStringConvertible, Decodable, CaseIterable {
public var description: String {
switch self {
@@ -122,20 +138,20 @@ public class PerseusLogger {
case fault = 1
}
- public enum TimeMultiply: String, Decodable {
+ public enum TimeMultiply: String, Decodable, CaseIterable {
// case millisecond // -3.
// case microsecond // -6.
case nanosecond // -9.
}
- public enum TIDNumber: String, Decodable {
+ public enum TIDNumber: String, Decodable, CaseIterable {
case hexadecimal
case decimal
}
- public enum MessageFormat: String, Decodable {
+ public enum MessageFormat: String, Decodable, CaseIterable {
- case short
+ case short // Depends on message details visibility flags.
// marks true, time false, owner false, directives false
// [DEBUG] message
@@ -164,16 +180,16 @@ public class PerseusLogger {
// marks false, time false, owner false, directives false
// message
- case full
+ case full // Forcefully. No matter what message details visibility flags are.
// [DEBUG] [2025-04-17] [20:31:53:630918979] [6317:0x2519d] message, file: File.swift, line: 29
- case textonly
+ case textonly // Forcefully. No matter what message details visibility flags are.
// message
}
// MARK: - Properties
- public static var customActionOnMessage: MessageDelegate?
+ public static var customActionOnMessage: PerseusLogger.MessageDelegate?
#if DEBUG
public static var turned = Status.on
@@ -188,17 +204,22 @@ public class PerseusLogger {
public static var subsecond = TimeMultiply.nanosecond
public static var tidnumber = TIDNumber.hexadecimal
+ // MARK: - Message Details Visibility Flags
+
public static var format = MessageFormat.short
- public static var marks = true // Controls tags [TYPE] [DATE] [TIME].
- public static var time = false // + [DATE] [TIME] to message. Depends on format and marks.
- public static var owner = false // + [PID:TID] to message. Depends on format.
- public static var directives = false // + File# and Line# to message. Depends on format.
+ // [TYPE] [DATE] [TIME] [PID:TID] message, file: #, line: #
+ public static var marks = true // [TYPE]
+ public static var time = false // [DATE] [TIME] Depends on format and marks
+ public static var owner = false // [PID:TID] Depends on format
+ public static var directives = false // file# and line# Depends on format
#if targetEnvironment(simulator)
- public static var debugIsInfo = true // Shows DEBUG message as INFO in macOS Console.app.
+ public static var debugIsInfo = true // Shows DEBUG message as INFO in macOS Console.
#endif
+ // MARK: - Special Properties
+
public static var logObject: ConsoleObject? {
didSet {
@@ -237,52 +258,26 @@ public class PerseusLogger {
// MARK: - Contract
- public static func loadConfig(_ profile: ProfileCPL) -> Bool {
- if let data = profile.json.data(using: .utf8) {
- if let jsonConfig = decodeJsonProfile(data) {
- reloadOptions(jsonConfig)
- return true
- }
- log.message("Failed to decode CPL json config data!", .error)
- return false
- }
- log.message("Failed to load CPL config data!", .error)
- return false
- }
-
- public static func loadConfig(_ json: URL) -> Bool {
- if FileManager.default.fileExists(atPath: json.relativePath) {
- if let data = try? Data(contentsOf: json) {
- if let jsonConfig = decodeJsonProfile(data) {
- reloadOptions(jsonConfig)
- return true
- }
- log.message("Failed to decode CPL json config data!", .error)
- return false
- }
- log.message("Failed to load CPL config data!", .error)
- return false
- }
- log.message("CPL config file doesn't exist!", .error)
- return false
- }
-
public static func message(_ text: @autoclosure () -> String,
_ type: Level = .debug,
_ oput: Output = PerseusLogger.output,
+ _ user: User = .operative,
_ file: StaticString = #file,
_ line: UInt = #line) {
- guard turned == .on, type.rawValue <= level.rawValue else { return }
+ guard turned == .on || user == .enduser, type.rawValue <= level.rawValue
+ else {
+ return
+ }
var message = ""
// Path.
let withDirectives = (format == .full) ? true : directives && (format != .textonly)
+ let fileName = (file.description as NSString).lastPathComponent
if withDirectives {
- let fileName = (file.description as NSString).lastPathComponent
message = "\(text()), file: \(fileName), line: \(line)"
} else {
message = "\(text())"
@@ -291,10 +286,10 @@ public class PerseusLogger {
// PID and TID.
let withOwnerId = (format == .full) ? true : owner && (format != .textonly)
- let idtuple = getPIDandTID()
+ let idTuple = getPIDandTID()
if withOwnerId {
- message = "[\(idtuple.pid):\(idtuple.tid)] \(message)"
+ message = "[\(idTuple.pid):\(idTuple.tid)] \(message)"
}
// Time.
@@ -314,12 +309,43 @@ public class PerseusLogger {
// Print.
if oput == .custom {
- customActionOnMessage?(message, type, localTime, idtuple)
+ let directives: Directives = (fileName: fileName, line: line)
+ customActionOnMessage?(message, type, localTime, idTuple, user, directives)
} else {
print(message, type, oput)
}
}
+ public static func loadConfig(_ profile: ProfileCPL) -> Bool {
+ if let data = profile.json.data(using: .utf8) {
+ if let jsonConfig = decodeJsonProfile(data) {
+ reloadOptions(jsonConfig)
+ return true
+ }
+ log.message("Failed to decode CPL json config data!", .error)
+ return false
+ }
+ log.message("Failed to load CPL config data!", .error)
+ return false
+ }
+
+ public static func loadConfig(_ json: URL) -> Bool {
+ if FileManager.default.fileExists(atPath: json.relativePath) {
+ if let data = try? Data(contentsOf: json) {
+ if let jsonConfig = decodeJsonProfile(data) {
+ reloadOptions(jsonConfig)
+ return true
+ }
+ log.message("Failed to decode CPL json config data!", .error)
+ return false
+ }
+ log.message("Failed to load CPL config data!", .error)
+ return false
+ }
+ log.message("CPL config file doesn't exist!", .error)
+ return false
+ }
+
// MARK: - Implementation
// swiftlint:disable:next cyclomatic_complexity
@@ -388,14 +414,19 @@ public class PerseusLogger {
private static func getLocalTime() -> LocalTime {
- guard let timezone = TimeZone(secondsFromGMT: 0) else { return ("TIME", "TIME") }
+ guard
+ let timezone = TimeZone(secondsFromGMT: 0)
+ else {
+ return ("TIME", "TIME", 0.0)
+ }
var calendar = Calendar.current
calendar.timeZone = timezone
calendar.locale = Locale(identifier: "en_US_POSIX")
- let current = Date(timeIntervalSince1970: (Date().timeIntervalSince1970 +
+ let UTC = Date().timeIntervalSince1970
+ let current = Date(timeIntervalSince1970: (UTC +
Double(TimeZone.current.secondsFromGMT())))
let details: Set =
@@ -410,7 +441,10 @@ public class PerseusLogger {
guard
let year = components.year,
let month = components.month?.toPrint,
- let day = components.day?.toPrint else { return ("TIME", "TIME") }
+ let day = components.day?.toPrint
+ else {
+ return ("TIME", "TIME", 0.0)
+ }
let date = "\(year)-\(month)-\(day)"
@@ -420,11 +454,14 @@ public class PerseusLogger {
let hour = components.hour?.toPrint, // Always in 24-hour.
let minute = components.minute?.toPrint,
let second = components.second?.toPrint,
- let subsecond = components.nanosecond?.multiply else { return ("TIME", "TIME") }
+ let subsecond = components.nanosecond?.multiply
+ else {
+ return ("TIME", "TIME", 0.0)
+ }
let time = "\(hour):\(minute):\(second):\(subsecond)"
- return (date: date, time: time)
+ return (date: date, time: time, timeUTC: UTC)
}
private static func getPIDandTID() -> PIDandTID {
@@ -445,7 +482,7 @@ public class PerseusLogger {
private static func reloadOptions(_ newValue: JsonOptionsCPL) {
logObject = (newValue.subsystem, newValue.category)
- // turned = newValue.turned // Ignored, only manually!
+ // turned = newValue.turned // Only manually!
level = newValue.level
output = newValue.output
subsecond = newValue.subsecond
@@ -477,11 +514,15 @@ private extension Int {
private extension UInt64 {
var hex: String {
- return "0x\(String(format: "%02x", self))"
+
+ let value = self
+ let valueFormated = String(format: "%02x", value)
+
+ return valueFormated
}
}
-// MARK: - Configuration Profiles
+// MARK: - JSON Profiles
private struct JsonOptionsCPL: CustomStringConvertible, Decodable {
let subsystem: String
@@ -594,3 +635,143 @@ private let defaultDebugProfile =
"debugIsInfo" : true
}
"""
+
+// MARK: - Log Report
+
+extension PerseusLogger {
+
+ public class Report: NSObject {
+
+ // MARK: - Internals
+
+ private var delegate: PerseusDelegatedMessage? // Delegate for end-user messages.
+ private var report = "" // Last messages.
+
+ // MARK: - Properties
+
+ @objc public dynamic var lastMessage: String = "" {
+ didSet {
+ resizeReportIfNeeded()
+ appendLastMessageToReport()
+ }
+ }
+
+ public var messageDelegate: AnyObject? {
+ didSet {
+ delegate = messageDelegate as? PerseusDelegatedMessage
+ }
+ }
+
+ public var text: String { report }
+
+ // MARK: - Constants
+
+ public let limit: Int
+ public let newLine: String
+
+#if os(iOS)
+ public static let limitDefault = 1000
+#elseif os(macOS)
+ public static let limitDefault = 3000
+#endif
+
+ // MARK: - Initializer
+
+ public init(limited: Int = Report.limitDefault, _ newLine: String = "\r\n--\r\n") {
+ self.limit = limited
+ self.newLine = newLine
+ }
+
+ // MARK: - Contract
+
+ // swiftlint:disable:next function_parameter_count
+ public func report(_ text: String,
+ _ type: Level,
+ _ localTime: LocalTime,
+ _ owner: PIDandTID,
+ _ user: User,
+ _ dirs: Directives) {
+
+ let text = text.replacingOccurrences(of: "\(type.tag) ", with: "")
+ lastMessage = "[\(localTime.date)] [\(localTime.time)] \(type.tag)\r\n\(text)"
+
+ if user == .enduser {
+ delegate?.message = text
+ }
+ }
+
+ public func clear() {
+ report = ""
+ }
+
+ // MARK: - Realization
+
+ private func resizeReportIfNeeded() {
+
+ let lmCount = lastMessage.count
+ let nlCount = newLine.count
+
+ // Can the last message be reported?
+ guard lmCount != 0, lmCount < limit else {
+ return
+ }
+
+ // Should the report be resized?
+ let length = lmCount + report.count + (report.isEmpty ? 0 : nlCount)
+ guard limit - length < 0 else {
+ return
+ }
+
+ // What length to remove?
+ let messages = report.components(separatedBy: newLine)
+ let messagesCount = messages.count - 1
+
+ var lengthToRemove = 0
+ var itemCount = 0
+
+ for item in messages {
+
+ itemCount += 1
+ let newLineLength = messagesCount == 0 ? 0 : nlCount
+
+ lengthToRemove += (item.count + newLineLength)
+
+ if itemCount == messagesCount, messagesCount > 2 {
+ lengthToRemove -= nlCount // There's no new line in the report end
+ }
+
+ // Is it enough?
+ let reportAfter = report.count - lengthToRemove
+ let lastMessageAfter = reportAfter != 0 ? nlCount + lmCount : lmCount
+
+ if limit - (reportAfter + lastMessageAfter) >= 0 {
+ break
+ }
+ }
+
+ // Final check
+ guard report.count >= lengthToRemove else {
+ return
+ }
+
+ // Free space
+ report.removeFirst(lengthToRemove)
+ }
+
+ private func appendLastMessageToReport() {
+
+ guard lastMessage.isEmpty == false, lastMessage.count < limit else {
+ return
+ }
+
+ let newLinelength = report.isEmpty ? 0 : newLine.count
+ let length = (lastMessage.count + report.count + newLinelength)
+
+ guard limit - length >= 0 else {
+ return
+ }
+
+ report.append(report.isEmpty ? lastMessage : newLine + lastMessage)
+ }
+ }
+}
diff --git a/Sources/PerseusDarkMode/TheDarkness.swift b/Sources/PerseusDarkMode/TheDarkness.swift
index fce37c5..32b18e2 100644
--- a/Sources/PerseusDarkMode/TheDarkness.swift
+++ b/Sources/PerseusDarkMode/TheDarkness.swift
@@ -5,20 +5,20 @@
//
// For iOS and macOS only. Use Stars to adopt for the specifics you need.
//
-// DESC: THE DARKNESS YOU CAN FORCE.
+// DESC: THE DARKNESS YOU CAN FORCE
//
// Created by Mikhail Zhigulin in 7530.
//
-// Copyright © 7530 - 7533 Mikhail Zhigulin of Novosibirsk
-// Copyright © 7533 PerseusRealDeal
+// Copyright © 7530 - 7534 Mikhail Zhigulin of Novosibirsk
+// Copyright © 7533 - 7534 PerseusRealDeal
//
// All rights reserved.
//
//
// MIT License
//
-// Copyright © 7530 - 7533 Mikhail A. Zhigulin of Novosibirsk
-// Copyright © 7533 PerseusRealDeal
+// Copyright © 7530 - 7534 Mikhail A. Zhigulin of Novosibirsk
+// Copyright © 7533 - 7534 PerseusRealDeal
//
// The year starts from the creation of the world according to a Slavic calendar.
// September, the 1st of Slavic year.