Add extensions to package
This commit is contained in:
parent
fa5ca2aa20
commit
a16a62b365
|
@ -5,6 +5,9 @@ import PackageDescription
|
|||
|
||||
let package = Package(
|
||||
name: "SwiftExtensions",
|
||||
platforms: [
|
||||
.iOS(.v14)
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||
.library(
|
||||
|
@ -21,8 +24,32 @@ let package = Package(
|
|||
.target(
|
||||
name: "SwiftExtensions",
|
||||
dependencies: []),
|
||||
.testTarget(
|
||||
name: "SwiftExtensionsTests",
|
||||
dependencies: ["SwiftExtensions"]),
|
||||
// .testTarget(
|
||||
// name: "SwiftExtensionsTests",
|
||||
// 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
|
||||
|
||||
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