Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb4d48d603 | |||
| 6604aae989 | |||
| ca7d2edcee | |||
| 3688549eb8 | |||
| f27a4f69ff | |||
| 2ac515b97e | |||
| 969f068480 | |||
| fbc2e6f8d2 | |||
| 8be6c81729 | |||
| 87c4706be8 | |||
| b4d6dc2602 | |||
| f859d197f3 | |||
| 3a11e233c7 | |||
| ddd4fdbb1f | |||
| 00394e0b9f | |||
| daea88df8f | |||
| b640c1d8ee | |||
| 2eaf72ed0e | |||
| 9e61ff3a85 | |||
| 204b871f17 | |||
| ecb41f1885 | |||
| dffbd8cbfd | |||
| 458e5fc29b | |||
| a6f335df01 | |||
| 106692fbfb | |||
| cb4dcfd07a | |||
| 419172104d |
@@ -1,10 +0,0 @@
|
||||
daysUntilStale: 7
|
||||
daysUntilClose: 7
|
||||
onlyLabels:
|
||||
- awaiting user input
|
||||
staleLabel: given up
|
||||
markComment: >
|
||||
🤖 This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions 🙂
|
||||
closeComment: false
|
||||
@@ -12,8 +12,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup fastlane
|
||||
run: brew install fastlane
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
brew install fastlane
|
||||
brew install cocoapods
|
||||
|
||||
- name: Publish release
|
||||
id: publish_release
|
||||
@@ -39,19 +41,10 @@ jobs:
|
||||
env:
|
||||
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
|
||||
run: |
|
||||
gem install cocoapods
|
||||
set -eo pipefail
|
||||
pod lib lint --allow-warnings
|
||||
pod trunk push --allow-warnings
|
||||
|
||||
- name: Communicate on PR released
|
||||
uses: unsplash/comment-on-pr@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
msg: |
|
||||
Congratulations! 🎉 This was released as part of [SkeletonView ${{ steps.publish_release.outputs.tag_name }}](${{ steps.publish_release.outputs.html_url }}) 🚀
|
||||
|
||||
- name: Tweet the release
|
||||
uses: ethomson/send-tweet-action@v1
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Issue Needs Attention
|
||||
# This workflow is triggered on issue comments.
|
||||
on:
|
||||
issue_comment:
|
||||
types: created
|
||||
|
||||
jobs:
|
||||
applyNeedsAttentionLabel:
|
||||
name: Apply Needs Attention Label
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Apply Needs Attention Label
|
||||
uses: hramos/needs-attention@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
response-required-label: 'awaiting user info'
|
||||
needs-attention-label: 'needs triage'
|
||||
@@ -0,0 +1,18 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 5 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
close-issue-message: 'Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.'
|
||||
stale-issue-message: '🤖 This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions 🙂'
|
||||
days-before-stale: 5
|
||||
days-before-close: 3
|
||||
enable-statistics: true
|
||||
operations-per-run: 60
|
||||
only-labels: 'awaiting user input'
|
||||
@@ -2,13 +2,8 @@
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
"platform" : "universal",
|
||||
"reference" : "systemBlueColor"
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ GEM
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.4)
|
||||
cocoapods-downloader (1.2.2)
|
||||
cocoapods-downloader (1.6.3)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
@@ -182,7 +182,7 @@ GEM
|
||||
tty-screen (0.7.0)
|
||||
tty-spinner (0.9.1)
|
||||
tty-cursor (~> 0.7)
|
||||
tzinfo (1.2.5)
|
||||
tzinfo (1.2.10)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:5.0
|
||||
// swift-tools-version:5.3
|
||||
|
||||
import PackageDescription
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<a href="https://cocoapods.org/pods/SkeletonView"><img src="https://img.shields.io/cocoapods/v/SkeletonView.svg?style=flat"></a>
|
||||
<a href="https://github.com/Carthage/Carthage/"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"></a>
|
||||
<a href="https://swift.org/package-manager/"><img src="https://img.shields.io/badge/SPM-supported-Green.svg?style=flat"></a>
|
||||
<img src="https://img.shields.io/badge/platforms-iOS_tvOS-green" />
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FJuanpe%2FSkeletonView%2Fbadge%3Ftype%3Dplatforms"/>
|
||||
<a href="https://badge.bow-swift.io/recipe?name=SkeletonView&description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting&url=https://github.com/juanpe/skeletonview&owner=Juanpe&avatar=https://avatars0.githubusercontent.com/u/1409041?v=4&tag=1.20.0"><img src="https://raw.githubusercontent.com/bow-swift/bow-art/master/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
|
||||
</p>
|
||||
|
||||
@@ -90,6 +90,10 @@ dependencies: [
|
||||
]
|
||||
```
|
||||
|
||||
> 📣 **IMPORTANT!**
|
||||
>
|
||||
> Since version 1.30.0, `SkeletonView` supports **XCFrameworks**, so if you want to install it as a **XCFramework**, please use [this repo](https://github.com/Juanpe/SkeletonView-XCFramework.git) instead.
|
||||
|
||||
|
||||
## 🐒 Usage
|
||||
|
||||
@@ -250,6 +254,7 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? // default: nil
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell? // default: nil
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareViewForSkeleton view: UICollectionReusableView, at indexPath: IndexPath)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.27.0"
|
||||
s.version = "1.30.2"
|
||||
s.summary = "An elegant way to show users that something is happening and also prepare them to which contents he is waiting"
|
||||
s.description = <<-DESC
|
||||
Today almost all apps have async processes, as API requests, long runing processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
|
||||
+3
@@ -15,6 +15,7 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier?
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell?
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareViewForSkeleton view: UICollectionReusableView, at indexPath: IndexPath)
|
||||
}
|
||||
|
||||
public extension SkeletonCollectionViewDataSource {
|
||||
@@ -35,6 +36,8 @@ public extension SkeletonCollectionViewDataSource {
|
||||
}
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath) { }
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareViewForSkeleton view: UICollectionReusableView, at indexPath: IndexPath) { }
|
||||
}
|
||||
|
||||
public protocol SkeletonCollectionViewDelegate: UICollectionViewDelegate { }
|
||||
|
||||
@@ -29,4 +29,8 @@ public struct SkeletonGradient {
|
||||
}
|
||||
}
|
||||
|
||||
public init(colors: [UIColor]) {
|
||||
self.gradientColors = colors
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
|
||||
at indexPath: IndexPath) -> UICollectionReusableView {
|
||||
if let viewIdentifier = originalCollectionViewDataSource?.collectionSkeletonView(collectionView, supplementaryViewIdentifierOfKind: kind, at: indexPath) {
|
||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: viewIdentifier, for: indexPath)
|
||||
|
||||
originalCollectionViewDataSource?.collectionSkeletonView(collectionView, prepareViewForSkeleton: view, at: indexPath)
|
||||
skeletonizeViewIfContainerSkeletonIsActive(container: collectionView, view: view)
|
||||
return view
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ struct SkeletonLayer {
|
||||
self.maskLayer.bounds = holder.definedMaxBounds
|
||||
self.maskLayer.cornerRadius = CGFloat(holder.skeletonCornerRadius)
|
||||
addTextLinesIfNeeded()
|
||||
self.maskLayer.tint(withColors: colors)
|
||||
self.maskLayer.tint(withColors: colors, traitCollection: holder.traitCollection)
|
||||
}
|
||||
|
||||
func update(usingColors colors: [UIColor]) {
|
||||
layoutIfNeeded()
|
||||
maskLayer.tint(withColors: colors)
|
||||
maskLayer.tint(withColors: colors, traitCollection: holder?.traitCollection)
|
||||
}
|
||||
|
||||
func layoutIfNeeded() {
|
||||
|
||||
@@ -106,9 +106,11 @@ extension UILabel: SkeletonTextNode {
|
||||
}
|
||||
|
||||
var fontLineHeight: CGFloat? {
|
||||
if let attributes = attributedText?.attributes(at: 0, effectiveRange: nil),
|
||||
let fontAttribute = attributes.first(where: { $0.key == .font }) {
|
||||
return fontAttribute.value as? CGFloat ?? font.lineHeight
|
||||
if let attributedText = attributedText,
|
||||
attributedText.length > 0 {
|
||||
let attributes = attributedText.attributes(at: 0, effectiveRange: nil)
|
||||
let fontAttribute = attributes.first(where: { $0.key == .font })
|
||||
return fontAttribute?.value as? CGFloat ?? font.lineHeight
|
||||
} else {
|
||||
return font.lineHeight
|
||||
}
|
||||
@@ -179,9 +181,11 @@ extension UITextView: SkeletonTextNode {
|
||||
}
|
||||
|
||||
var fontLineHeight: CGFloat? {
|
||||
if let attributes = attributedText?.attributes(at: 0, effectiveRange: nil),
|
||||
let fontAttribute = attributes.first(where: { $0.key == .font }) {
|
||||
return fontAttribute.value as? CGFloat ?? font?.lineHeight
|
||||
if let attributedText = attributedText,
|
||||
attributedText.length > 0 {
|
||||
let attributes = attributedText.attributes(at: 0, effectiveRange: nil)
|
||||
let fontAttribute = attributes.first(where: { $0.key == .font })
|
||||
return fontAttribute?.value as? CGFloat ?? font?.lineHeight
|
||||
} else {
|
||||
return font?.lineHeight
|
||||
}
|
||||
|
||||
@@ -21,7 +21,18 @@ extension UITableView {
|
||||
// Some developer trying to call `view.showAnimatedSkeleton()`
|
||||
// when the request or data is loading which sometimes happens before the ViewDidAppear
|
||||
guard window != nil else { return [] }
|
||||
return subviews
|
||||
|
||||
var result = [UIView]()
|
||||
|
||||
for subview in subviews {
|
||||
if String(describing: type(of: subview)) == "UITableViewWrapperView" {
|
||||
result.append(contentsOf: subview.subviews)
|
||||
} else {
|
||||
result.append(subview)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,11 +15,15 @@ import UIKit
|
||||
|
||||
extension CAGradientLayer {
|
||||
|
||||
override func tint(withColors colors: [UIColor]) {
|
||||
override func tint(withColors colors: [UIColor], traitCollection: UITraitCollection?) {
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
self.colors = colors.map { $0.cgColor }
|
||||
if #available(iOS 13.0, tvOS 13, *), let traitCollection = traitCollection {
|
||||
self.colors = colors.map { $0.resolvedColor(with: traitCollection).cgColor }
|
||||
} else {
|
||||
self.colors = colors.map { $0.cgColor }
|
||||
}
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
$0.tint(withColors: colors, traitCollection: traitCollection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +39,15 @@ extension CALayer {
|
||||
return sublayers?.filter { $0.name == Constants.skeletonSubLayersName } ?? [CALayer]()
|
||||
}
|
||||
|
||||
@objc func tint(withColors colors: [UIColor]) {
|
||||
@objc func tint(withColors colors: [UIColor], traitCollection: UITraitCollection?) {
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
backgroundColor = colors.first?.cgColor
|
||||
if #available(iOS 13.0, tvOS 13, *), let traitCollection = traitCollection {
|
||||
backgroundColor = colors.first?.resolvedColor(with: traitCollection).cgColor
|
||||
} else {
|
||||
backgroundColor = colors.first?.cgColor
|
||||
}
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
$0.tint(withColors: colors, traitCollection: traitCollection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +86,7 @@ extension CALayer {
|
||||
insertSublayer(sublayer.contentLayer, at: index)
|
||||
switch transition {
|
||||
case .none:
|
||||
completion?()
|
||||
DispatchQueue.main.async { completion?() }
|
||||
case .crossDissolve(let duration):
|
||||
sublayer.contentLayer.setOpacity(from: 0, to: 1, duration: duration, completion: completion)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,13 @@ public extension UIColor {
|
||||
}
|
||||
|
||||
var complementaryColor: UIColor {
|
||||
isLight ? darker : lighter
|
||||
if #available(iOS 13, tvOS 13, *) {
|
||||
return UIColor { _ in
|
||||
self.isLight ? self.darker : self.lighter
|
||||
}
|
||||
} else {
|
||||
return isLight ? darker : lighter
|
||||
}
|
||||
}
|
||||
|
||||
var lighter: UIColor {
|
||||
|
||||
+2
-2
@@ -22,11 +22,11 @@ extension UIView {
|
||||
func startObservingAppLifecycleNotifications() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: .applicationDidBecomeActiveNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: .applicationDidEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willTerminateNotification), name: .applicationDidEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willTerminateNotification), name: .applicationWillTerminateNotification, object: nil)
|
||||
}
|
||||
|
||||
func stopObservingAppLifecycleNotications() {
|
||||
NotificationCenter.default.removeObserver(self, name: .applicationDidEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .applicationDidBecomeActiveNotification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .applicationDidEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .applicationWillTerminateNotification, object: nil)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user