Skip to content

Commit

Permalink
Merge pull request #3 from klassen-software-solutions/development/v1
Browse files Browse the repository at this point in the history
Development/v1
  • Loading branch information
stevenklassen8376 committed Sep 8, 2020
2 parents 0c12814 + f7f03a3 commit c1be9b9
Show file tree
Hide file tree
Showing 45 changed files with 3,599 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/on-push.yml
@@ -0,0 +1,27 @@
name: On Push

on: [push]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- uses: actions/checkout@v1

- name: Build
if: |
!startsWith(github.event.head_commit.message, 'WIP')
&& !startsWith(github.ref, 'refs/tags/')
run: |
git submodule update --init --recursive
make
- name: Run tests
if: |
!startsWith(github.event.head_commit.message, 'WIP')
&& !startsWith(github.ref, 'refs/tags/')
run: |
make check
25 changes: 25 additions & 0 deletions .github/workflows/on-release.yml
@@ -0,0 +1,25 @@
name: On Release

on:
release:
types: [published]

jobs:
docs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1

- name: Install Jazzy
run: |
sudo gem install jazzy
- name: Publish Docs
env:
X_URL: ${{ secrets.API_PUBLISHER_URL }}
X_USER: ${{ secrets.API_PUBLISHER_USER }}
X_PW: ${{ secrets.API_PUBLISHER_PASSWORD }}
run: |
git submodule update --init --recursive
make docs
BuildSystem/common/publish.py --url "$X_URL" --user "$X_USER" --password "$X_PW" docs
7 changes: 7 additions & 0 deletions .gitignore
@@ -0,0 +1,7 @@
.build
.swiftpm
docs
docs.zip
Package.resolved
REVISION

3 changes: 3 additions & 0 deletions .gitmodules
@@ -0,0 +1,3 @@
[submodule "BuildSystem"]
path = BuildSystem
url = https://github.com/klassen-software-solutions/BuildSystem.git
1 change: 1 addition & 0 deletions BuildSystem
Submodule BuildSystem added at 4fd2ed
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
@@ -0,0 +1,10 @@
# Contributing to KSSCoreUI

If you are going to contribute to this project, please make yourself familiar with our standards and
procedures:

* [Git Procedures](https://www.kss.cc/standards-git.html)
* [Swift Coding Standards](https://www.kss.cc/standards-swift.html)

Note that the iOS version is not currently included in the CI. That may change as we work on
more iOS projects, but for now the iOS version of the tests must be run manually within Xcode.
21 changes: 21 additions & 0 deletions Dependencies/prereqs-licenses.json
@@ -0,0 +1,21 @@
{
"dependencies": [
{
"moduleLicense": "MIT License",
"moduleName": "KSSCore",
"moduleUrl": "https://github.com/klassen-software-solutions/KSSCore.git",
"moduleVersion": "4.0.0",
"x-isOsiApproved": true,
"x-licenseTextEncoded": "TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAxOSBLbGFzc2VuIFNvZnR3YXJlIFNvbHV0aW9ucwoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weQpvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbAppbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzCnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwKY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzCmZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwKY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCklNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLApGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUKQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUgpMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLApPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQpTT0ZUV0FSRS4K",
"x-spdxId": "MIT",
"x-usedBy": [
"KSSCoreUI"
]
}
],
"generated": {
"process": "license-scanner",
"project": "KSSCoreUI",
"time": "2020-09-07T16:55:55.642169-06:00"
}
}
4 changes: 4 additions & 0 deletions Makefile
@@ -0,0 +1,4 @@
AUTHOR := Klassen Software Solutions
AUTHOR_URL := https://www.kss.cc/

include BuildSystem/swift/common.mk
30 changes: 30 additions & 0 deletions Package.swift
@@ -0,0 +1,30 @@
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "KSSCoreUI",
platforms: [
.macOS(.v10_11),
.iOS(.v13),
],
products: [
.library(name: "KSSMap", targets: ["KSSMap"]),
.library(name: "KSSNativeUI", targets: ["KSSNativeUI"]),
.library(name: "KSSSwiftUI", targets: ["KSSSwiftUI"]),
.library(name: "KSSWeb", targets: ["KSSWeb"]),
],
dependencies: [
.package(url: "https://github.com/klassen-software-solutions/KSSCore.git", from: "4.0.0"),
],
targets: [
.target(name: "KSSNativeUI", dependencies: [.product(name: "KSSFoundation", package: "KSSCore")]),
.target(name: "KSSMap", dependencies: []),
.target(name: "KSSSwiftUI", dependencies: ["KSSNativeUI"]),
.target(name: "KSSWeb", dependencies: []),
.testTarget(name: "KSSNativeUITests", dependencies: ["KSSNativeUI", .product(name: "KSSTest", package: "KSSCore")]),
.testTarget(name: "KSSSwiftUITests", dependencies: ["KSSSwiftUI", .product(name: "KSSTest", package: "KSSCore")]),
.testTarget(name: "KSSWebTests", dependencies: ["KSSWeb"]),
]
)
27 changes: 27 additions & 0 deletions README.md
@@ -1,2 +1,29 @@
# KSSCoreUI
Miscellaneous Swift UI utilities

## Description

This package is divided into a number of Swift Modules providing utility methods related to UI
classes. A key feature of this package is that it has no dependencies other than the KSSCore
libraries and a standard Apple development environment.

The modules provided by this package are the following:

* _KSSMap_ - items that depend on MapKit
* _KSSNativeUI - items that depend on either Cocoa (macOS) or UIKit (iOS)
* _KSSSwiftUI_ - items that depend on SwiftUI
* _KSSWeb_ - items that depend on WebKit

[API Documentation](https://www.kss.cc/apis/KSSCoreUI/docs/index.html)

## Module Availability

Note that not all modules are available on all architectures. In addition, within a module there will
be things that are only available on some architectures. For example, anything that depends on
Cocoa will be available on _macOS_ but not on _iOS_.

Presently we support the following:

* _macOS_ - All modules are available
* _iOS_ - All modules are available, except for `KSSWeb`.

68 changes: 68 additions & 0 deletions Sources/KSSMap/MKMapViewExtension.swift
@@ -0,0 +1,68 @@
//
// MKMapViewExtension.swift
// KSSCore
//
// Created by Steven W. Klassen on 2019-03-08.
// Copyright © 2019 Klassen Software Solutions. All rights reserved.
//

import MapKit

public extension MKMapView {
/**
scrollToCurrentLocation will obtain the user's current location and attempt to
scroll that map to that position.
*/
func scrollToCurrentLocation() {
if isScrollEnabled {
if let coord = userLocation.location?.coordinate{
setCenter(coord, animated: true)
}
}
}

/**
zoomIn zooms the map in approximately the same amount as a single click on
the zoom controls. If zooming is not enabled, then this does nothing.
*/
func zoomIn() {
doZoom(0.5)
}

/**
zoomOut zooms the map out approximately the same amount as a single click on
the zoom controls. If zooming is not enabled, then this does nothing.
*/
func zoomOut() {
doZoom(2)
}

/**
snapToNorth rotates the map, if necessary, in order to point it north. If already
pointing north or if rotations are not enabled, then this does nothing.
*/
func snapToNorth() {
if isRotateEnabled && camera.heading != 0 {
let c = MKMapCamera(lookingAtCenter: camera.centerCoordinate,
fromDistance: camera.altitude,
pitch: camera.pitch,
heading: 0)
setCamera(c, animated: true)
}
}

private func doZoom(_ factor: Double) {
if isZoomEnabled {
let r = region
let s = MKCoordinateSpan(latitudeDelta: min(r.span.latitudeDelta * factor, 180),
longitudeDelta: min(r.span.longitudeDelta * factor, 180))
setRegion(MKCoordinateRegion(center: r.center, span: s), animated: true)

// Most of the time snapToNorth will do nothing, since setRegion will have
// already done this, but when rotated near the poles, and already zoomed out,
// setRegion will do nothing. Hence we call this so that our result is
// reasonably close to that of using the zoom controls.
snapToNorth()
}
}
}
84 changes: 84 additions & 0 deletions Sources/KSSNativeUI/NSApplicationExtension.swift
@@ -0,0 +1,84 @@
//
// NSApplicationExtension.swift
// WSTerminal
//
// Created by Steven W. Klassen on 2020-02-25.
// Copyright © 2020 Klassen Software Solutions. All rights reserved.
//

#if canImport(Cocoa)

import Cocoa
import KSSFoundation


public extension NSApplication {

/**
Return the name of the application as read from the bundle. Note that as the name is a required
key in the bundle, if it does not exist this will cause a fatal error.
*/
var name: String { Bundle.main.infoDictionary![kCFBundleNameKey as String] as! String }

/**
Return the version of the application as read from the bundle. Note that as the verion is an optional
key in the bundle, this may return nil.
*/
var version: String? { Bundle.main.infoDictionary!["CFBundleShortVersionString"] as? String }

/**
Return the build number of the application as read from the bundle. Note that as the build number is a required
key in the bundle, if it does not exist, or if it cannot be converted to an integer, this will cause a fatal error.
- warning: If the bundle version includes a decimal point (which may be true during library unit testing) it will
be rounded down to the nearest integer.
*/
var buildNumber: Int { Int(Double(Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String)!) }


/**
Search for and create if necessary a common directory for the containing application.
- parameters:
- directory: The directory we are searching for.
- domain: The search domain.
- throws:
Any error that FileManager.findOrCreateDirectory may throw.
- returns:
The URL of the found directory.
*/
func findOrCreateApplicationDirectory(for directory: FileManager.SearchPathDirectory,
in domain: FileManager.SearchPathDomainMask) throws -> URL
{
// Determine the required directory path.
let fileManager = FileManager.default
let commonURL = try fileManager.url(for: directory,
in: domain,
appropriateFor: nil,
create: true)
let applicationDirectoryURL = commonURL.appendingPathComponent(self.name)

// Find or create it.
try fileManager.findOrCreateDirectory(at: applicationDirectoryURL,
withIntermediateDirectories: true)
return applicationDirectoryURL
}

/**
Returns true if the current appearance is a dark mode appearance.
*/
var isDarkMode: Bool {
if #available(OSX 10.15, *) {
let appearanceDescription = effectiveAppearance.debugDescription.lowercased()
return appearanceDescription.contains("dark")
} else {
if let appleInterfaceStyle = UserDefaults.standard.object(forKey: "AppleInterfaceStyle") as? String {
return appleInterfaceStyle.lowercased().contains("dark")
}
return false
}
}
}
#endif
23 changes: 23 additions & 0 deletions Sources/KSSNativeUI/NSColor+errorHighlightColor.swift
@@ -0,0 +1,23 @@
//
// NSColor+errorHighlightColor.swift
// HTTPMonitor
//
// Created by Steven W. Klassen on 2020-08-13.
// Copyright © 2020 Klassen Software Solutions. All rights reserved.
// Released under the MIT license.
//

#if canImport(Cocoa)

import Cocoa
import Foundation


public extension NSColor {
/// Specifies the color to be used for highlighting errors. Typically this would be used as a background,
/// but it can also be used as a foreground color if you add `.withAlphaComponent(1)` to make
/// it stand out better.
class var errorHighlightColor: NSColor { NSColor.systemYellow.withAlphaComponent(0.50) }
}

#endif
41 changes: 41 additions & 0 deletions Sources/KSSNativeUI/NSFontExtension.swift
@@ -0,0 +1,41 @@
//
// NSFontExtension.swift
// WSTerminal
//
// Created by Steven W. Klassen on 2020-02-11.
// Copyright © 2020 Klassen Software Solutions. All rights reserved.
//

#if canImport(Cocoa)

import Cocoa

public extension NSFont {

/**
Returns a font like the existing one but with the specified traits.
- returns:
The new font or nil if the conversion could not be made.
*/
func withTraits(traits: NSFontDescriptor.SymbolicTraits) -> NSFont? {
let descriptor = fontDescriptor.withSymbolicTraits(traits)
return NSFont(descriptor: descriptor, size: 0)
}

/**
Returns a new font like the existing one but converted to bold.
*/
func bold() -> NSFont {
return withTraits(traits: .bold)!
}

/**
Returns a new font like the existing one but converted to italic.
*/
func italic() -> NSFont {
return withTraits(traits: .italic)!
}
}

#endif

0 comments on commit c1be9b9

Please sign in to comment.