Add extensions to package
This commit is contained in:
parent
fa5ca2aa20
commit
a16a62b365
|
@ -5,6 +5,9 @@ import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "SwiftExtensions",
|
name: "SwiftExtensions",
|
||||||
|
platforms: [
|
||||||
|
.iOS(.v14)
|
||||||
|
],
|
||||||
products: [
|
products: [
|
||||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||||
.library(
|
.library(
|
||||||
|
@ -21,8 +24,32 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "SwiftExtensions",
|
name: "SwiftExtensions",
|
||||||
dependencies: []),
|
dependencies: []),
|
||||||
.testTarget(
|
// .testTarget(
|
||||||
name: "SwiftExtensionsTests",
|
// name: "SwiftExtensionsTests",
|
||||||
dependencies: ["SwiftExtensions"]),
|
// dependencies: ["SwiftExtensions"]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
name: "textStickersSwiftUIViews",
|
||||||
|
platforms: [
|
||||||
|
.iOS(.v14)
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||||
|
.library(
|
||||||
|
name: "textStickersSwiftUIViews",
|
||||||
|
targets: ["textStickersSwiftUIViews"]),
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
// Dependencies declare other packages that this package depends on.
|
||||||
|
// .package(url: /* package url */, from: "1.0.0"),
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||||
|
.target(
|
||||||
|
name: "textStickersSwiftUIViews",
|
||||||
|
dependencies: [])
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# SwiftExtensions
|
# SwiftExtensions
|
||||||
|
|
||||||
A description of this package.
|
Handy extensions for use in different projects.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// AnyTransition+scaleAndFade.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 16/02/2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension AnyTransition {
|
||||||
|
static var scaleAndFade: AnyTransition {
|
||||||
|
let insertion = AnyTransition.scale
|
||||||
|
.combined(with: .opacity)
|
||||||
|
let removal = AnyTransition.scale
|
||||||
|
.combined(with: .opacity).animation(Animation.easeOut.speed(10))
|
||||||
|
return .asymmetric(insertion: insertion, removal: removal)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// Array+removeDuplicates.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 17/02/2021.
|
||||||
|
//
|
||||||
|
// extensoin from Paul Hudson - https://www.hackingwithswift.com/example-code/language/how-to-remove-duplicate-items-from-an-array
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/*
|
||||||
|
provides two methods: one called removingDuplicates() that returns an array with duplicates removed, and one called removeDuplicates() that changes the array in place.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extension Array where Element: Hashable {
|
||||||
|
func removingDuplicates() -> [Element] {
|
||||||
|
var addedDict = [Element: Bool]()
|
||||||
|
|
||||||
|
return filter {
|
||||||
|
addedDict.updateValue(true, forKey: $0) == nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func removeDuplicates() {
|
||||||
|
self = self.removingDuplicates()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Bindig+didSet.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 26/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Binding {
|
||||||
|
func didSet(execute: @escaping (Value) -> Void) -> Binding {
|
||||||
|
return Binding(
|
||||||
|
get: {
|
||||||
|
return self.wrappedValue
|
||||||
|
},
|
||||||
|
set: {
|
||||||
|
self.wrappedValue = $0
|
||||||
|
execute($0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// Color+fromString+ToString.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 25/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Color {
|
||||||
|
func toString() -> String {
|
||||||
|
let uiColor = UIColor(self)
|
||||||
|
var red: CGFloat = 0
|
||||||
|
var green: CGFloat = 0
|
||||||
|
var blue: CGFloat = 0
|
||||||
|
var alpha: CGFloat = 0
|
||||||
|
|
||||||
|
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
||||||
|
|
||||||
|
return "\(red),\(green),\(blue),\(alpha)"
|
||||||
|
}
|
||||||
|
|
||||||
|
static func fromString(_ string: String) -> Color {
|
||||||
|
let rgbArray = string.components(separatedBy: ",")
|
||||||
|
if let red = Double(rgbArray[0]), let green = Double(rgbArray[1]), let blue = Double(rgbArray[2]), let alpha = Double(rgbArray[3]) {
|
||||||
|
return Color(.sRGB, red: red, green: green, blue: blue, opacity: alpha)
|
||||||
|
} else {
|
||||||
|
return Color.pink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// Color+random.swift
|
||||||
|
// kaomojiEmoticonKeyboard (iOS)
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 24/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Color {
|
||||||
|
static var random: Color {
|
||||||
|
[Color.red, Color.orange, Color.yellow, Color.blue, Color.purple, Color.pink, Color.green].randomElement()!
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
//
|
||||||
|
// View+directories.swift
|
||||||
|
// kaomojiEmoticonKeyboard (iOS)
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 24/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class Directories {
|
||||||
|
|
||||||
|
// Get user's documents directory path
|
||||||
|
static func getDocumentsDirectoryPath() -> URL {
|
||||||
|
let arrayPaths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
|
||||||
|
let docDirectoryPath = arrayPaths[0]
|
||||||
|
return docDirectoryPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user's cache directory path
|
||||||
|
static func getCacheDirectoryPath() -> URL {
|
||||||
|
let arrayPaths = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
|
||||||
|
let cacheDirectoryPath = arrayPaths[0]
|
||||||
|
return cacheDirectoryPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user's temp directory path
|
||||||
|
static func getTempDirectoryPath() -> URL {
|
||||||
|
let tempDirectoryPath = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
||||||
|
return tempDirectoryPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user's temp directory path
|
||||||
|
static func getAppSharedGroupPath() -> URL? {
|
||||||
|
let sharedContainerURL :URL? = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.net.tarasis.kaomojiEmoticonKeyboard")
|
||||||
|
|
||||||
|
return sharedContainerURL
|
||||||
|
}
|
||||||
|
|
||||||
|
static func clearCache(){
|
||||||
|
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
do {
|
||||||
|
// Get the directory contents urls (including subfolders urls)
|
||||||
|
let directoryContents = try FileManager.default.contentsOfDirectory( at: cacheURL, includingPropertiesForKeys: nil, options: [])
|
||||||
|
for file in directoryContents {
|
||||||
|
do {
|
||||||
|
try fileManager.removeItem(at: file)
|
||||||
|
}
|
||||||
|
catch let error as NSError {
|
||||||
|
debugPrint("Ooops! Something went wrong: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch let error as NSError {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func clearAppGroup(){
|
||||||
|
guard let cacheURL = getAppSharedGroupPath() else { fatalError("Error getting app group url") }
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
do {
|
||||||
|
// Get the directory contents urls (including subfolders urls)
|
||||||
|
let directoryContents = try FileManager.default.contentsOfDirectory( at: cacheURL, includingPropertiesForKeys: nil, options: [])
|
||||||
|
for file in directoryContents {
|
||||||
|
do {
|
||||||
|
try fileManager.removeItem(at: file)
|
||||||
|
}
|
||||||
|
catch let error as NSError {
|
||||||
|
debugPrint("Ooops! Something went wrong: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch let error as NSError {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func clearCachedStickers(){
|
||||||
|
guard let cacheURL = getAppSharedGroupPath() else { fatalError("Error getting app group url") }
|
||||||
|
|
||||||
|
let stickerDirectoryPath = cacheURL.appendingPathComponent("Stickers")
|
||||||
|
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
do {
|
||||||
|
// Get the directory contents urls (including subfolders urls)
|
||||||
|
let directoryContents = try FileManager.default.contentsOfDirectory( at: stickerDirectoryPath, includingPropertiesForKeys: nil, options: [])
|
||||||
|
for file in directoryContents {
|
||||||
|
do {
|
||||||
|
try fileManager.removeItem(at: file)
|
||||||
|
}
|
||||||
|
catch let error as NSError {
|
||||||
|
debugPrint("Ooops! Something went wrong: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch let error as NSError {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// String+subscript.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 16/02/2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
subscript(idx: Int) -> String {
|
||||||
|
String(self[index(startIndex, offsetBy: idx)])
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
struct SwiftExtensions {
|
|
||||||
var text = "Hello, World!"
|
|
||||||
}
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// File.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 26/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension UIHostingController {
|
||||||
|
|
||||||
|
func capture(transparentBackground: Bool = true) -> UIImage {
|
||||||
|
let size = sizeThatFits(in: UIScreen.main.bounds.size)
|
||||||
|
// makes background transparent
|
||||||
|
if (transparentBackground) {
|
||||||
|
view.backgroundColor = UIColor.clear
|
||||||
|
view.isOpaque = false
|
||||||
|
view.layer.isOpaque = false
|
||||||
|
view.layer.backgroundColor = UIColor.clear.cgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
view.bounds.size = size
|
||||||
|
view.sizeToFit()
|
||||||
|
|
||||||
|
//suggested version
|
||||||
|
// UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0)
|
||||||
|
// view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
|
||||||
|
// let snapshotImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
// UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
//cleaner ver
|
||||||
|
let renderer = UIGraphicsImageRenderer(size: self.view.bounds.size)
|
||||||
|
let snapshotImage = renderer.image { ctx in
|
||||||
|
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshotImage
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// UIImage+scaleImage.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 28/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UIImage {
|
||||||
|
func resizeImage(newWidth: CGFloat) -> UIImage? {
|
||||||
|
|
||||||
|
let scale = newWidth / self.size.width
|
||||||
|
let newHeight = self.size.height * scale
|
||||||
|
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
|
||||||
|
self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
|
||||||
|
|
||||||
|
let newImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func scaleToSize(_ newSize: CGSize) -> UIImage? {
|
||||||
|
var newImage: UIImage?
|
||||||
|
let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral
|
||||||
|
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
|
||||||
|
if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
|
||||||
|
context.interpolationQuality = .high
|
||||||
|
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height)
|
||||||
|
context.concatenate(flipVertical)
|
||||||
|
context.draw(cgImage, in: newRect)
|
||||||
|
if let img = context.makeImage() {
|
||||||
|
// newImage = UIImage(cgImage: img) -- orig
|
||||||
|
let scale = UIScreen.main.scale
|
||||||
|
newImage = UIImage(cgImage: img, scale: scale, orientation: .up)
|
||||||
|
}
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
}
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func scaleToWidth(_ newWidth: CGFloat) -> UIImage? {
|
||||||
|
var newImage: UIImage?
|
||||||
|
let scale = newWidth / self.size.width
|
||||||
|
let newHeight = self.size.height * scale
|
||||||
|
|
||||||
|
let newRect = CGRect(x: 0, y: 0, width: newWidth, height: newHeight).integral
|
||||||
|
UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: newHeight), false, 0)
|
||||||
|
if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
|
||||||
|
context.interpolationQuality = .high
|
||||||
|
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newHeight)
|
||||||
|
context.concatenate(flipVertical)
|
||||||
|
context.draw(cgImage, in: newRect)
|
||||||
|
if let img = context.makeImage() {
|
||||||
|
// newImage = UIImage(cgImage: img) -- orig
|
||||||
|
let scale = UIScreen.main.scale
|
||||||
|
newImage = UIImage(cgImage: img, scale: scale, orientation: .up)
|
||||||
|
}
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
}
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't need, kept because erm
|
||||||
|
// static func scaleImage(_ image: UIImage, toNewWidth newWidth: CGFloat) -> UIImage? {
|
||||||
|
// var newImage: UIImage?
|
||||||
|
// let scale = newWidth / image.size.width
|
||||||
|
// let newHeight = image.size.height * scale
|
||||||
|
//
|
||||||
|
// let newRect = CGRect(x: 0, y: 0, width: newWidth, height: newHeight).integral
|
||||||
|
// UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: newHeight), false, 0)
|
||||||
|
// if let context = UIGraphicsGetCurrentContext(), let cgImage = image.cgImage {
|
||||||
|
// context.interpolationQuality = .high
|
||||||
|
// let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newHeight)
|
||||||
|
// context.concatenate(flipVertical)
|
||||||
|
// context.draw(cgImage, in: newRect)
|
||||||
|
// if let img = context.makeImage() {
|
||||||
|
// // newImage = UIImage(cgImage: img) -- orig
|
||||||
|
// let scale = UIScreen.main.scale
|
||||||
|
// newImage = UIImage(cgImage: img, scale: scale, orientation: .up)
|
||||||
|
// }
|
||||||
|
// UIGraphicsEndImageContext()
|
||||||
|
// }
|
||||||
|
// return newImage
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// View+glow.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 18/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func glow(color: Color = .red, radius: CGFloat = 20) -> some View {
|
||||||
|
self
|
||||||
|
.overlay(self.blur(radius: radius / 6))
|
||||||
|
.shadow(color: color, radius: radius / 3)
|
||||||
|
.shadow(color: color, radius: radius / 3)
|
||||||
|
.shadow(color: color, radius: radius / 3)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// View+hideKeyboard.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 15/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func hideKeyboard() {
|
||||||
|
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// View+multicolorGlow.swift
|
||||||
|
// kaomojiEmoticonKeyboard
|
||||||
|
//
|
||||||
|
// Created by Robert McGovern on 18/11/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func multicolorGlow() -> some View {
|
||||||
|
ForEach(0..<2) { i in
|
||||||
|
Rectangle()
|
||||||
|
.fill(AngularGradient(gradient: Gradient(colors: [.red, .yellow, .green, .blue, .purple, .red]), center: .center))
|
||||||
|
.frame(width: 50, height: 50)
|
||||||
|
.mask(self.blur(radius: 20))
|
||||||
|
.overlay(self.blur(radius: 5 - CGFloat(i * 5)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import XCTest
|
|
||||||
@testable import SwiftExtensions
|
|
||||||
|
|
||||||
final class SwiftExtensionsTests: XCTestCase {
|
|
||||||
func testExample() {
|
|
||||||
// This is an example of a functional test case.
|
|
||||||
// Use XCTAssert and related functions to verify your tests produce the correct
|
|
||||||
// results.
|
|
||||||
XCTAssertEqual(SwiftExtensions().text, "Hello, World!")
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue