diff --git a/APPROBATION.md b/APPROBATION.md index 83f656a..bd41971 100644 --- a/APPROBATION.md +++ b/APPROBATION.md @@ -1,10 +1,18 @@ -# Approbation Matrix / PerseusGeoLocationKit 1.0.0 && 1.0.1 && 1.0.2 && 1.0.2 && 1.0.3 && 1.0.4 && 1.1.0 && 1.1.1 && 1.1.2 +# Approbation Matrix for PerseusGeoLocationKit + +## Approbated Versions + +> This report is actual for the following product versions: + +v1.0.0 v1.0.1 v1.0.2 v1.0.2 v1.0.3 v1.0.4 v1.1.0 v1.1.1 v1.1.2 **v1.2.0** + +## Approbation Note > NOTE: To catch all log messages Mac Console should be started first then after a little while the logged app. > Compilation: macOS Monterey 12.7.6 / Xcode 14.2 -## macOS approbation result +# macOS approbation result > The macOS app used to approbate PerseusGeoLocationKit is [Arkenstone](https://github.com/perseusrealdeal/Arkenstone). @@ -19,7 +27,7 @@ | Sonoma | 14.7 | ok | Returns LS status .notDetermed if turn LS off, OpenCore usage case. | | Sequoia | 15.1 | ok | Returns LS status .notDetermed if turn LS off, OpenCore usage case. | -## iOS approbation result +# iOS approbation result > The iOS app used to approbate PerseusGeoLocationKit is [The One Ring](https://github.com/perseusrealdeal/TheOneRing). @@ -28,9 +36,9 @@ | iPad Air | no | 12.5.7 | ok | - | | iPhone SE (3rd) | yes | 16.2 | ok | Simulator generates error on every event of currentLocation/start but value received | -## A3 environment +# A3 environment -### List of available Apple machines +## List of available Apple machines > Excluded: virtualization (e.g. VirtualBox) and hackintosh @@ -39,7 +47,7 @@ | Mac mini | 16GB | SATA 480GB, NVMe 256GB | | MacBook Pro | 8GB | 256GB | -### System configuration for A3 environment +## System configuration for A3 environment | macOS | Version | Machine | Xcode | OpenCore | Git Client | | ----------- | ------- | ----------- | ------ | -------- | -------------- | diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef9a84..0cccbc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,37 @@ 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. -## [1.1.2] - [2025-12-14], PGK +## [1.2.0] - [2026-03-03], PerseusGeoKit + +### Included + +- The support code to the main code. + +### Renamed + +- `PGKStar.swift` to `TheGeoStar.swift`. + +### Added: + +- Minor changes to documentation. + +### Updated: + +- CPL dependency to v1.7.1. + +## [1.1.2] - [2025-12-14], PerseusGeoKit ### Added: - Calculated property to ActionAlertText to simplify complex localization issues. -## [1.1.1] - [2025-11-30], PGK +## [1.1.1] - [2025-11-30], PerseusGeoKit ### Updated - CPL dependency to v1.7.0. -## [1.1.0] - [2025-10-30], PGK +## [1.1.0] - [2025-10-30], PerseusGeoKit ### Added @@ -27,7 +45,7 @@ Dates in this file meets Gregorian calendar. Date in format YYYY-MM-DD. - CPL dependency to v1.6.0. -## [1.0.4] - [2025-07-22], PGK +## [1.0.4] - [2025-07-22], PerseusGeoKit ### Removed @@ -38,25 +56,25 @@ Dates in this file meets Gregorian calendar. Date in format YYYY-MM-DD. - GitHub CI scripts. - CPL dependency to v1.5.1. -## [1.0.3] - [2025-06-18], PGK +## [1.0.3] - [2025-06-18], PerseusGeoKit ### Fixed - Logger access modifier, typealias `log` must be not public. -## [1.0.2] - [2025-06-17], PGK +## [1.0.2] - [2025-06-17], PerseusGeoKit ### Upgraded - PerseusLogger to [CPL v1.5.0](https://github.com/perseusrealdeal/ConsolePerseusLogger). -## [1.0.1] - [2025-05-31], PGK +## [1.0.1] - [2025-05-31], PerseusGeoKit ### Fixed - iOS: Location Services permission request if status in .notDetermined. -## [1.0.0] - [2025-05-31], PGK +## [1.0.0] - [2025-05-31], PerseusGeoKit - Minimum build requirements: macOS 10.13+, iOS 11.0+, Xcode 14.2+. If standalone Xcode 10.1+. diff --git a/LICENSE b/LICENSE index 3acc76a..d5a098b 100644 --- a/LICENSE +++ b/LICENSE @@ -4,9 +4,9 @@ Copyright © 7531 - 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. +September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. -Use Stars to adopt for the specifics you need. +Stars to adopt for the specifics you need. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Package.swift b/Package.swift index de899b7..3a8ba95 100644 --- a/Package.swift +++ b/Package.swift @@ -1,7 +1,7 @@ // swift-tools-version:5.7 /* Package.swift - Version: 1.1.2 + Version: 1.2.0 For iOS and macOS only. Use Stars to adopt for the specifics you need. diff --git a/README.md b/README.md index 3a74981..e5ff2b4 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,25 @@ -# PerseusGeoKit — Xcode 14.2+ +
+ +Perseus Geo Kit +== + +HAVE A DEAL WITH WHERE YOU ARE [![Actions Status](https://github.com/perseusrealdeal/PerseusGeoKit/actions/workflows/main.yml/badge.svg)](https://github.com/perseusrealdeal/PerseusGeoKit/actions/workflows/main.yml) [![Style](https://github.com/perseusrealdeal/PerseusGeoKit/actions/workflows/swiftlint.yml/badge.svg)](https://github.com/perseusrealdeal/PerseusGeoKit/actions/workflows/swiftlint.yml) -[![Version](https://img.shields.io/badge/Version-1.1.2-green.svg)](/CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-1.2.0-green.svg)](/CHANGELOG.md) [![Platforms](https://img.shields.io/badge/Platforms-macOS%2010.13+_|_iOS%2011.0+-orange.svg)](https://en.wikipedia.org/wiki/List_of_Apple_products) [![Xcode 14.2](https://img.shields.io/badge/Xcode-14.2+-red.svg)](https://en.wikipedia.org/wiki/Xcode) [![Swift 5.7](https://img.shields.io/badge/Swift-5.7-red.svg)](https://www.swift.org) -[![License](http://img.shields.io/:License-MIT-blue.svg)](/LICENSE) -> This is the great home-made product in Swift for easily managed `Location Services API`. +[`A3 Environment`](/APPROBATION.md) • [`CHANGELOG`](/CHANGELOG.md) • [`MIT License`](/LICENSE) + +
+ +--- + +Usages +== > `1:` Be awared of Location Services Status.
> `2:` Request permission for Location Services.
@@ -16,45 +27,42 @@ > `4:` Get Current Location.
> `5:` Request Location Updates. -> `PGK` is a single author and personale solution developed in `P2P` relationship paradigm. - -## Integration Capabilities +Integration +== -[![Standalone](https://img.shields.io/badge/Standalone%20-available-informational.svg)](/PGKStar.swift) +[![Standalone](https://img.shields.io/badge/Standalone%20-available-informational.svg)](/TheGeoStar.swift) [![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-4BC51D.svg)](/Package.swift) -## Dependencies +Dependencies +== -[![ConsolePerseusLogger](http://img.shields.io/:ConsolePerseusLogger-1.7.0-green.svg)](https://github.com/perseusrealdeal/ConsolePerseusLogger.git) +[![ConsolePerseusLogger](http://img.shields.io/:ConsolePerseusLogger-1.7.1-green.svg)](https://github.com/perseusrealdeal/ConsolePerseusLogger.git) -## Support Code +Support Code +== -[![Standalone](https://img.shields.io/badge/Standalone-available-informational.svg)](/PGKSupportingStar.swift) +[![Standalone](https://img.shields.io/badge/Standalone-available-informational.svg)](/Sources/PerseusGeoKit/TheGeoSupport.swift) [![License](http://img.shields.io/:License-Unlicense-green.svg)](http://unlicense.org/) -> [`PGKSupportingStar.swift`](/PGKSupportingStar.swift) is a peace of code a widly helpful in accord with PGK.
-> `PGKSupportingStar.swift` goes as an external part of PGK. +> [`TheGeoSupport.swift`](/Sources/PerseusGeoKit/TheGeoSupport.swift) is a peace of code a widly helpful in accord with `PGK`. -## Our Terms +PGK in Use +== -> [`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. +> `Approbation:` -## PGK in Use +- [`Swift macOS app`](https://github.com/perseusrealdeal/Arkenstone) +- [`Swift iOS app`](https://github.com/perseusrealdeal/TheOneRing) -> `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) +> `Business:` -> `For details:` [`Approbation and A3 Environment`](/APPROBATION.md) / [`CHANGELOG`](/CHANGELOG.md)
+- Swift macOS app [`The Dark Moon`](https://github.com/perseusrealdeal/TheDarkMoon) -# Contents +Contents +== * [In brief](#In-brief) -* [Build requirements](#Build-requirements) +* [Requirements](#Requirements) * [First-party software](#First-party-software) * [Third-party software](#Third-party-software) * [Installation](#Installation) @@ -68,22 +76,44 @@ * [Location status](#Location-status) * [Current location](#Current-location) * [Location updates](#Location-updates) -* [Points taken into account](#Points-taken-into-account) +* [Account points](#Account-points) * [License](#License) - * [Other required license notices](#Other-required-license-notices) + * [Other required licenses details](#Other-required-licenses-details) * [Credits](#Credits) +* [Contributing](#Contributing) * [Author](#Author) + * [Contact](#Contact) + +Our Terms +-- -# In brief +| Acronym | Stands for | +| :-----: | --------------------------------------------------------------------------------------------------------- | +| CPL | [Console_Perseus_Logger](https://github.com/perseusrealdeal/ConsolePerseusLogger.git) | +| PDM | [Perseus_Dark_Mode](https://github.com/perseusrealdeal/PerseusDarkMode.git) | +| PGK | [Perseus_Geo_Kit](https://github.com/perseusrealdeal/PerseusGeoKit.git) | +| A3 | [Apple_Apps_Approbation](https://docs.google.com/document/d/1K2jOeIknKRRpTEEIPKhxO2H_1eBTof5uTXxyOm5g6nQ) | +| T3 | [The_Technological_Tree](https://github.com/perseusrealdeal/TheTechnologicalTree) | +| P2P | Person_to_Person | -> HAVE A DEAL WITH WHERE YOU ARE
+In brief +== + +The great home-made product for easily managed `Location Services API`. `PGK` is a single author and personale solution developed in `P2P` relationship paradigm. - - + + + -
Approbation App: iOS 16.2Approbation App: macOS MontereymacOS appiOS app
+
+ The Current Location Dialog
+
+ System Services and The Redirect Dialog
+ +

The Current Location Dialog
@@ -93,44 +123,56 @@ System Services
-
- The Current Location Dialog
-
- System Services and The Redirect Dialog
- -
-> [!NOTE] -> [`The iOS App`](https://github.com/perseusrealdeal/TheOneRing) scenes taken from the motion picture `The Lord of The Rings` based on the novel by J.R.R. Tolkien.
-> [`The macOS App`](https://github.com/perseusrealdeal/Arkenstone) scenes taken from the motion picture `The Hobbit` based on the novel by J.R.R. Tolkien. +> [!IMPORTANT] +> [`The macOS App`](https://github.com/perseusrealdeal/Arkenstone) scenes taken from the motion picture `The Hobbit` based on the novel by J.R.R. Tolkien.
+> [`The iOS App`](https://github.com/perseusrealdeal/TheOneRing) scenes taken from the motion picture `The Lord of The Rings` based on the novel by J.R.R. Tolkien. + +Requirements +== + +`To build:` + +- [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) -# Build system requirements +First-party software +== -- [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) +MIT +-- -# First-party software +| Type | Name | +| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Star | [ConsolePerseusLogger](https://github.com/perseusrealdeal/ConsolePerseusLogger) / [1.7.1](https://github.com/perseusrealdeal/ConsolePerseusLogger/releases/tag/1.7.1) | -| Type | Name | License | -| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| Star | [ConsolePerseusLogger](https://github.com/perseusrealdeal/ConsolePerseusLogger) / [1.7.0](https://github.com/perseusrealdeal/ConsolePerseusLogger/releases/tag/1.7.0) | MIT | +Third-party software +== -# Third-party software +MIT +-- -| Type | Name | License | -| ------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| Style | [SwiftLint](https://github.com/realm/SwiftLint) / [v0.57.0 for Monterey+](https://github.com/realm/SwiftLint/releases/tag/0.57.0) | MIT | -| Script | [SwiftLint Shell Script](/SucceedsPostAction.sh) to run SwiftLint | MIT | -| Action | [mxcl/xcodebuild@v3](https://github.com/mxcl/xcodebuild) | [Unlicense](https://unlicense.org) | -| Action | [cirruslabs/swiftlint-action@v1](https://github.com/cirruslabs/swiftlint-action/) | MIT | +| Type | Name | +| ------ | --------------------------------------------------------------------------------------------------------------------------------- | +| Style | [SwiftLint](https://github.com/realm/SwiftLint) / [v0.57.0 for Monterey+](https://github.com/realm/SwiftLint/releases/tag/0.57.0) | +| Script | [SwiftLint Shell Script](/SucceedsPostAction.sh) to run SwiftLint | +| Action | [cirruslabs/swiftlint-action@v1](https://github.com/cirruslabs/swiftlint-action/) | -# Installation +[Unlicense](https://unlicense.org) +-- + +| Type | Name | +| ------ | --------------------------------------------------------------------------------------------------------------------------------- | +| Action | [mxcl/xcodebuild@v3](https://github.com/mxcl/xcodebuild) | + +Installation +== `Step 1:` Import PGK either with SPM or standalone. -> Standalone: the single source code file [PGKStar.swift](/PGKStar.swift) +> Standalone: the single source code file [TheGeoStar.swift](/TheGeoStar.swift) > Swift Package Manager: `https://github.com/perseusrealdeal/PerseusGeoKit` @@ -143,9 +185,11 @@ `Step 3, macOS:` Tap `Location` in `App Sandbox` of your project target. -# Usage +Usage +== -## Get location services status +Get location services status +-- Location Services Status is calculated as a unified value for both iOS and macOS. @@ -165,7 +209,7 @@ let statusInDetail = GeoAgent.aboutLocationServices().inDetail |.notAllowed |.deniedForTheApp |Location Services turned on but the app not restricted. | |.allowed |.allowed |Authorized. | -> [!IMPORTANT] +> [!NOTE] > To be awared of Location Services Status changes, register: ```swift @@ -182,7 +226,8 @@ GeoAgent.register(self, #selector(locationStatusHandler(_:)), .locationStatus) ``` -## Request permission +Request permission +-- Statement **GeoAgent.requestPermission()** can be combined with the action to be called if status has already determined. @@ -214,7 +259,7 @@ GeoAgent.showRedirectAlert(REDIRECT_ALERT_TITLES) ``` -> [!NOTE] +> [!IMPORTANT] > `iOS:` The Redirect Dialog by **GeoAgent.showRedirectAlert(vc)** requires the parent ViewController. ```swift @@ -227,7 +272,8 @@ GeoAgent.shared.requestPermission { status in ``` -## Request current location +Request current location +-- > [!WARNING] > Statement **GeoAgent.shared.requestCurrentLocation()** causes stop updating location. @@ -269,7 +315,8 @@ do { ``` -## Request updating location +Request updating location +-- `Step 1:` Register for Geo events both error and updating location. @@ -317,7 +364,8 @@ GeoAgent.shared.stopUpdatingLocation() ``` -## Geo events processing +Geo events processing +-- ### Location error @@ -484,60 +532,87 @@ GeoAgent.register(self, #selector(locationUpdatesHandler(_:)), .locationUpdates) ``` -# Points taken into account +Account points +== - Preconfigured Swift Package manifest [Package.swift](/Package.swift) - Preconfigured SwiftLint config [.swiftlint.yml](/.swiftlint.yml) - Preconfigured SwiftLint CI [swiftlint.yml](/.github/workflows/swiftlint.yml) - Preconfigured GitHub config [.gitignore](/.gitignore) - Preconfigured GitHub CI [main.yml](/.github/workflows/main.yml) +- [Changelog](/CHANGELOG.md) +- [A3 environment specification](/APPROBATION.md) +- [SwiftLint shell script](/SucceedsPostAction.sh) -# License +License +== -`License:` MIT +`MIT License`, see [LICENSE](/LICENSE) for details. Copyright © 7531 - 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, 2025" is the beginning of 7534. - -## Other required license notices +- September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. -© 2025 The SwiftLint Contributors **for** SwiftLint
-© GitHub **for** GitHub Action cirruslabs/swiftlint-action@v1
-© 2021 Alexandre Colucci, geteimy.com **for** Shell Script SucceedsPostAction.sh
+Other required licenses details +-- -[LICENSE](/LICENSE) for details. +`© 2025 The SwiftLint Contributors` **for** SwiftLint
+`© GitHub` **for** GitHub Action cirruslabs/swiftlint-action@v1
+`© 2021 Alexandre Colucci, geteimy.com` **for** Shell Script SucceedsPostAction.sh
-## Credits +Credits +== - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
Balance and Controlkept byMikhail Zhigulin
Source Codewritten byMikhail Zhigulin
Documentationprepared byMikhail Zhigulin
Product Approbationtested byMikhail Zhigulin
Balance and ControlMikhail Zhigulin
Source CodeMikhail Zhigulin
DocumentationMikhail Zhigulin
ApprobationMikhail Zhigulin
EnglishMikhail Zhigulin
- Language support: [Reverso](https://www.reverso.net/) - Git clients: [SmartGit](https://syntevo.com/) and [GitHub Desktop](https://github.com/apps/desktop) -# Author +Contributing +== + +> [!NOTE] +> The product is constructed in `P2P` relationship paradigm that means the only one single and the same face in the product team during all development process stages. + +`Bug reports are welcome`, create an issue and give details. + +Author +== + +
+ +`© Mikhail A. Zhigulin of Novosibirsk` + +
+ +Contact +-- + +
+ +[E-mail](mailto:mzhigulin@gmail.com) • [Telegram](https://t.me/velociraptor1985) • [GitHub](https://github.com/perseusrealdeal) -> © Mikhail A. Zhigulin of Novosibirsk. +
diff --git a/PGKSupportingStar.swift b/Sources/PerseusGeoKit/TheGeoSupport.swift similarity index 98% rename from PGKSupportingStar.swift rename to Sources/PerseusGeoKit/TheGeoSupport.swift index 2ff29c1..32ccdee 100644 --- a/PGKSupportingStar.swift +++ b/Sources/PerseusGeoKit/TheGeoSupport.swift @@ -1,16 +1,15 @@ // -// PGKSupportingStar.swift -// Version: 1.1.2 +// TheGeoSupport.swift // // PerseusGeoKit Support Code // // -// For iOS and macOS only. Use Stars to adopt for the specifics you need. +// Stars to adopt for the specifics you need. // // Created by Mikhail Zhigulin of Novosibirsk in 7533. // // 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, 2025" is the beginning of 7534. +// September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. // // // Unlicensed Free Software diff --git a/Sources/PerseusGeoKit/CPLStar.swift b/Sources/PerseusGeoKit/TheLoggerStar.swift similarity index 99% rename from Sources/PerseusGeoKit/CPLStar.swift rename to Sources/PerseusGeoKit/TheLoggerStar.swift index 26ddbb1..d3eb6dc 100644 --- a/Sources/PerseusGeoKit/CPLStar.swift +++ b/Sources/PerseusGeoKit/TheLoggerStar.swift @@ -1,10 +1,10 @@ // -// CPLStar.swift -// Version: 1.7.0 +// TheLoggerStar.swift +// Version: 1.7.1 // // Standalone ConsolePerseusLogger. // -// For iOS and macOS. Use Stars to adopt for the specifics you need. +// Stars to adopt for the specifics you need. // // DESC: USE LOGGER LIKE A VARIABLE ANYWHERE YOU WANT. // @@ -27,7 +27,7 @@ // Copyright © 7531 - 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, 2025" is the beginning of 7534. +// September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/PGKStar.swift b/TheGeoStar.swift similarity index 70% rename from PGKStar.swift rename to TheGeoStar.swift index be6c872..5334570 100644 --- a/PGKStar.swift +++ b/TheGeoStar.swift @@ -1,11 +1,11 @@ // -// PerseusGeoKitStar.swift -// Version: 1.1.2 +// TheGeoStar.swift +// Version: 1.2.0 // // Standalone PerseusGeoKit // // -// For iOS and macOS only. Use Stars to adopt for the specifics you need. +// Stars to adopt for the specifics you need. // // DESC: HAVE A DEAL WITH WHERE YOU ARE. // @@ -23,7 +23,7 @@ // 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, 2025" is the beginning of 7534. +// September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -54,8 +54,6 @@ import UIKit import Cocoa #endif -// import ConsolePerseusLogger - // MARK: - Constants public let APPROPRIATE_ACCURACY_DEFAULT = GeoAccuracy.threeKilometers @@ -1073,3 +1071,372 @@ public func redirectToSettingsApp() { } #endif + +// MARK: - The Geo Support +// +// The Geo Support +// +// +// Stars to adopt for the specifics you need. +// +// Created by Mikhail Zhigulin of Novosibirsk in 7533. +// +// The year starts from the creation of the world according to a Slavic calendar. +// September, the 1st of Slavic year. For instance, "Sep 01, 2025" is the beginning of 7534. +// +// +// Unlicensed Free Software +// Sstarting from here and further in the file +// +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to +// + +import MapKit + +// MARK: - Geo Constants + +let DEFAULT_ACCURACY: GeoAccuracy = .threeKilometers + +let DEFAULT_MAP_POINT = CLLocation(latitude: 55.036857, longitude: 82.914063) +let DEFAULT_MAP_RADIUS: CLLocationDistance = 1000 + +let DEFAULT_VISIBLE_REGION = MKCoordinateRegion(center: DEFAULT_MAP_POINT.coordinate, + latitudinalMeters: DEFAULT_MAP_RADIUS, + longitudinalMeters: DEFAULT_MAP_RADIUS) + +var REDIRECT_ALERT_TITLES = ActionAlertText( + title: "Location Services.", + message: "The Current Location Services Status can be changed in System Services.", + buttonCancel: "OK", + buttonFunction: "System Services") + +extension ActionAlertText { + var titleWithStatus: String { + guard let status = titleCalculated else { + return "Location Services: \(GeoAgent.currentStatus.description.capitalized)." + } + return status() + } +} + +extension Notification.Name { + static let ReloadGeoDataNotification = Notification.Name("ReloadGeoDataNotification") +} + +#if os(iOS) + +extension UIView { + + func parentViewController() -> UIViewController? { + + guard let responder = self.next as? UIViewController else { + guard let responder = self.next as? UIView else { + return nil + } + + return responder.parentViewController() + } + + return responder + } +} + +#endif + +// MARK: - LocationDealer class + +class LocationDealer { + + // MARK: - iOS Contract + +#if os(iOS) + + public class func requestPermission(_ alertViewController: UIViewController? = nil) { + GeoAgent.shared.requestPermission { status in + if status != .allowed, let parentVC = alertViewController { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(parentVC, REDIRECT_ALERT_TITLES) // Offer redirect. + } + } + } + + public class func requestCurrent(_ alertViewController: UIViewController? = nil) { + do { + try GeoAgent.shared.requestCurrentLocation() + } catch LocationError.permissionRequired(let status) { // Permission required. + + log.message("[\(type(of: self))].\(#function) permission required", .notice) + + if status == .notDetermined { + GeoAgent.shared.requestPermission() // Request permission. + } else if let parentVC = alertViewController { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(parentVC, REDIRECT_ALERT_TITLES) // Offer redirect. + } + + } catch { + log.message("[\(type(of: self))].\(#function) something went wrong", .error) + } + } + + public class func requestUpdatingLocation(_ alertViewController: UIViewController? = nil) { + do { + try GeoAgent.shared.requestUpdatingLocation() + } catch LocationError.permissionRequired(let status) { // Permission required. + + if status == .notDetermined { + GeoAgent.shared.requestPermission() // Request permission. + } else if let parentVC = alertViewController { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(parentVC, REDIRECT_ALERT_TITLES) // Offer redirect. + } + + } catch { + log.message("[\(type(of: self))].\(#function) something went wrong", .error) + } + } + +#elseif os(macOS) + + // MARK: - macOS Contract + + public class func requestPermission() { + GeoAgent.shared.requestPermission { status in + if status != .allowed { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(REDIRECT_ALERT_TITLES) // Offer redirect. + } + } + } + + public class func requestCurrent() { + do { + try GeoAgent.shared.requestCurrentLocation() + } catch LocationError.permissionRequired(let status) { // Permission required. + + log.message("[\(type(of: self))].\(#function) permission required", .notice) + + if status == .notDetermined { + GeoAgent.shared.requestPermission() // Request permission. + } else { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(REDIRECT_ALERT_TITLES) // Offer redirect. + } + + } catch { + log.message("[\(type(of: self))].\(#function) something went wrong", .error) + } + } + + public class func requestUpdatingLocation() { + do { + try GeoAgent.shared.requestUpdatingLocation() + } catch LocationError.permissionRequired(let status) { // Permission required. + + if status == .notDetermined { + GeoAgent.shared.requestPermission() // Request permission. + } else { + REDIRECT_ALERT_TITLES.title = REDIRECT_ALERT_TITLES.titleWithStatus + GeoAgent.showRedirectAlert(REDIRECT_ALERT_TITLES) // Offer redirect. + } + + } catch { + log.message("[\(type(of: self))].\(#function) something went wrong", .error) + } + } + +#endif + +} + +// MARK: - GeoCoordinator class + +class GeoCoordinator: NSObject { + + // MARK: - Properties + + public var notifier: NotificationCenter? + + public var locationRecieved: ((GeoPoint) -> Void)? + public var locationUpdatesRecieved: (([GeoPoint]) -> Void)? + + public var onStatusAllowed: (() -> Void)? + + // MARK: - Singletone + + public static let shared = GeoCoordinator() + + private override init() { + + log.message("[\(GeoCoordinator.self)].\(#function)", .info) + + super.init() + + GeoAgent.register(self, #selector(locationErrorHandler(_:)), .locationError) + GeoAgent.register(self, #selector(locationStatusHandler(_:)), .locationStatus) + GeoAgent.register(self, #selector(currentLocationHandler(_:)), .currentLocation) + GeoAgent.register(self, #selector(locationUpdatesHandler(_:)), .locationUpdates) + } + + // MARK: - Contract + + public static func register(stakeholder: Any, selector: Selector) { + shared.notifier?.addObserver(stakeholder, + selector: selector, + name: .ReloadGeoDataNotification, + object: nil) + } + + public static func reloadGeoComponents() { + log.message("[\(type(of: self))].\(#function)") + shared.updateGeoComponents() + } + + // MARK: - Implementation + + private func updateGeoComponents() { + log.message("[\(type(of: self))].\(#function)") + self.notifier?.post(name: .ReloadGeoDataNotification, object: nil) + } + + // MARK: - Event Handlers + + @objc private func locationErrorHandler(_ notification: Notification) { + + log.message("[\(type(of: self))].\(#function) [EVENT]") + var errtext = "" + + guard let error = notification.object as? LocationError else { + errtext = "nothing is about error" + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + return + } + + switch error { + case .failedRequest(let desc, let domain, let code): + let domaincode = "domain: \(domain), code: \(code)" + if desc.contains("[NOTKNOWN]") { + errtext = "\(desc), \(domaincode)" + } else { + switch code { + case 0: + errtext = "hardware issue: try to tap Wi-Fi in system tray, \(domaincode)" + case 1: + errtext = "permission required, \(domaincode)" + default: + break + } + } + default: + break + } + + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + } + + @objc private func locationStatusHandler(_ notification: Notification) { + + guard let sysStatus = notification.object as? CLAuthorizationStatus else { + let errtext = "nothing is about status event" + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + return + } + + let lmStatus = GeoAgent.aboutLocationServices().auth + + if lmStatus != sysStatus { + let statues = "lm status: \(lmStatus), system status: \(sysStatus)" + log.message("[\(type(of: self))].\(#function) \(statues)", .error) + } + + let status = GeoAgent.currentStatus + + log.message("[\(type(of: self))].\(#function) currentStatus: \(status) [EVENT]") + + updateGeoComponents() + + if status == .allowed { + onStatusAllowed?() + } + } + + @objc private func currentLocationHandler(_ notification: Notification) { + + log.message("[\(type(of: self))].\(#function) [EVENT]") + + var errtext = "" + var location: GeoPoint? + + guard let result = notification.object as? Result else { + errtext = "nothing is about location" + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + return + } + + switch result { + case .success(let point): + location = point + case .failure(let error): + errtext = "\(error)" + } + + if let current = location { + locationRecieved?(current) + } else if !errtext.isEmpty { + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + } + + updateGeoComponents() + } + + @objc private func locationUpdatesHandler(_ notification: Notification) { + log.message("[\(type(of: self))].\(#function) [EVENT]") + + var errtext = "" + var updates: [GeoPoint]? + + guard let result = notification.object as? Result<[GeoPoint], LocationError> else { + errtext = "nothing is about location updates" + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + return + } + + switch result { + case .success(let points): + updates = points + case .failure(let error): + errtext = "\(error)" + } + + if let updates = updates { + locationUpdatesRecieved?(updates) + } else if !errtext.isEmpty { + log.message("[\(type(of: self))].\(#function) \(errtext)", .error) + } + + updateGeoComponents() + } +}