Add + Update screen : PlayMusic

This commit is contained in:
mrustaa
2024-07-31 15:59:53 +03:00
parent 18c90f0c63
commit 85d52cd837
107 changed files with 2883 additions and 392 deletions
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020 Pavel Puzyrev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
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 OR COPYRIGHT HOLDERS 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.
@@ -0,0 +1,58 @@
# Blurberry
Transparent blur using UIVisualEffectView without subclassing.
![GIF Demo](https://github.com/unboxme/Blurberry/blob/master/Resources/demo.gif)
[[video demo]](https://vimeo.com/457206677)
[[appetize demo]](https://appetize.io/app/u2udhgwh0cgm12at0rmgjxtphr)
## Features
- Based on UIVisualEffectView
- Supports **iOS 14** and animation blocks
- Super safe and super easy
## Usage
Just create a `UIVisualEffectView` in any way. Code, storyboards, XIBs, etc.
Customize it like example bellow via `blur` wrapper:
```swift
visualEffectView.blur.radius = 5.0
visualEffectView.blur.tintColor = .clear
```
Don't forget to set a `tintColor` value, otherwise it will be 30% white like `UIBlurEffect.Style.Light` by default.
## Installation
### Cocoapods
Add the Blurberry pod to your Podfile:
```ruby
platform :ios, '10.0'
use_frameworks!
target 'BlurryApp' do
pod 'Blurberry'
end
```
## Next Steps
- [x] iOS 10, 11, 12 support
- [ ] Other platform support (such as macOS)
- [ ] Remove ObjC code or make it private
- [ ] Add manager to check blur availability and other service info
- [ ] Hide private API class names, method names, etc.
## Disclaimer
This framework uses private API, so just keep in mind it before submitting to the AppStore.
## Requirements
- iOS 10.0+
- Swift 5
@@ -0,0 +1,37 @@
//
// Blurberry.h
// Blurberry
//
// Created by Pavel Puzyrev on 09.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
#import <Foundation/Foundation.h>
//! Project version number for Blurberry.
FOUNDATION_EXPORT double BlurberryVersionNumber;
//! Project version string for Blurberry.
FOUNDATION_EXPORT const unsigned char BlurberryVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Blurberry/PublicHeader.h>
#import <Blurberry/NSObject+Extension.h>
@@ -0,0 +1,63 @@
//
// NSObject+Extension.h
// Blurberry
//
// Created by Pavel Puzyrev on 07.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
#import <Foundation/Foundation.h>
#import "ContainerControllerSwift-Swift.h"
struct BlurWrapper;
@class UIColor;
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Extension)
#pragma mark *** Values getting ***
- (nullable NSArray<NSObject *> *)arrayValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(arrayValue(getter:));
- (nullable NSDictionary<NSString *, id> *)dictionaryValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(dictionaryValue(getter:));
- (nullable NSString *)stringValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(stringValue(getter:));
- (nullable UIColor *)colorValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(colorValue(getter:));
#pragma mark *** Values setting ***
- (void)setIVarValue:(nullable id)value getterNamed:(NSString *)getterName NS_SWIFT_NAME(setIVarValue(value:getter:));
- (void)setValueUsingSetter:(nullable id)value getterNamed:(NSString *)getterName NS_SWIFT_NAME(setValueUsingSetter(value:getter:));
- (void)setObjectInDictionary:(id)object
forKey:(NSString *)key
getterNamed:(NSString *)getterName NS_SWIFT_NAME(setObjectInDictionary(object:key:getter:));
- (nullable id)valueSafeForKey:(NSString *)key NS_SWIFT_NAME(valueSafe(key:));
- (void)setValueSafe:(id)value forKey:(NSString *)key NS_SWIFT_NAME(setValueSafe(value:key:));
#pragma mark *** Methods calling ***
- (void)callMethodNamed:(NSString *)methodName NS_SWIFT_NAME(callMethod(named:));
- (void)callMethodNamed:(NSString *)methodName withObject:(nullable id)argument NS_SWIFT_NAME(callMethod(named:with:));
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,161 @@
//
// NSObject+Extension.m
// Blurberry
//
// Created by Pavel Puzyrev on 07.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
#import "NSObject+Extension.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
//@class BlurWrapper;
NS_ASSUME_NONNULL_BEGIN
@implementation NSObject (Extension)
#pragma mark - Public Methods
#pragma mark *** Values getting ***
- (nullable NSArray<NSObject *> *)arrayValueByGetterNamed:(NSString *)getterName {
return [self valueOfType:[NSArray class] getterNamed:getterName];
}
- (nullable NSDictionary<NSString *, id> *)dictionaryValueByGetterNamed:(NSString *)getterName {
return [self valueOfType:[NSDictionary class] getterNamed:getterName];
}
- (nullable NSString *)stringValueByGetterNamed:(NSString *)getterName {
return [self valueOfType:[NSString class] getterNamed:getterName];
}
- (nullable UIColor *)colorValueByGetterNamed:(NSString *)getterName {
return [self valueOfType:[UIColor class] getterNamed:getterName];
}
#pragma mark *** Values setting ***
- (void)setIVarValue:(nullable id)value getterNamed:(NSString *)getterName {
@try {
SEL getterSelector = NSSelectorFromString(getterName);
SEL setterSelector = NSSelectorFromString([self setterMethodName:getterName]);
NSString *ivarName = [NSString stringWithFormat:@"_%@", getterName];
if ([self respondsToSelector:getterSelector] && [self respondsToSelector:setterSelector]) {
[self setValue:value forKey:ivarName];
}
} @catch (NSException *exception) {
}
}
- (void)setValueUsingSetter:(nullable id)value getterNamed:(NSString *)getterName {
[self callMethodNamed:[self setterMethodName:getterName] withObject:value];
}
- (void)setObjectInDictionary:(id)object forKey:(NSString *)key getterNamed:(NSString *)getterName {
NSMutableDictionary *dictionary = [[self dictionaryValueByGetterNamed:getterName] mutableCopy];
if (!dictionary) {
return;
}
dictionary[key] = object;
[self callMethodNamed:[self setterMethodName:getterName] withObject:[dictionary copy]];
}
- (nullable id)valueSafeForKey:(NSString *)key {
@try {
return [self valueForKey:key];
} @catch (NSException *exception) {
return nil;
}
}
- (void)setValueSafe:(id)value forKey:(NSString *)key {
@try {
[self setValue:value forKey:key];
} @catch (NSException *exception) {
}
}
#pragma mark *** Methods calling ***
- (void)callMethodNamed:(NSString *)methodName {
[self callMethodNamed:methodName withObject:nil];
}
- (void)callMethodNamed:(NSString *)methodName withObject:(nullable id)argument {
@try {
SEL selector = NSSelectorFromString(methodName);
if ([self respondsToSelector:selector]) {
_Pragma("clang diagnostic push")
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")
if (argument) {
[self performSelector:selector withObject:argument];
} else {
[self performSelector:selector];
}
_Pragma("clang diagnostic pop")
}
} @catch (NSException *exception) {
}
}
#pragma mark - Private Methods
- (nullable id)valueOfType:(Class)type getterNamed:(NSString *)getterName {
id typedValue;
@try {
SEL selector = NSSelectorFromString(getterName);
if ([self respondsToSelector:selector]) {
_Pragma("clang diagnostic push")
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")
id value = [self performSelector:selector];
if ([value isKindOfClass:type]) {
typedValue = value;
}_Pragma("clang diagnostic pop")
}
} @catch (NSException *exception) {
} @finally {
return typedValue;
}
}
- (NSString *)setterMethodName:(NSString *)getterMethodName {
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
NSString *firstChar = [getterMethodName substringToIndex:1];
NSString *folded = [firstChar stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:locale];
NSString *pascalCasedResult = [folded.uppercaseString stringByAppendingString:[getterMethodName substringFromIndex:1]];
return [NSString stringWithFormat:@"set%@:", pascalCasedResult];
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,50 @@
//
// Blurberry.swift
// Blurberry
//
// Created by Pavel Puzyrev on 09.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
import UIKit
public struct BlurWrapper<Base> {
public let base: Base
public init(_ base: Base) {
self.base = base
}
}
public protocol BlurCompatible: AnyObject { }
public extension BlurCompatible {
var blur: BlurWrapper<Self> {
get {
BlurWrapper(self)
}
set { }
}
}
extension UIVisualEffectView: BlurCompatible { }
@@ -0,0 +1,89 @@
//
// VisualEffectView+Internal.swift
// Blurberry
//
// Created by Pavel Puzyrev on 07.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
import UIKit
internal extension BlurWrapper where Base: UIVisualEffectView {
// MARK: iOS 13, 14
var backdropView: UIView? {
base.subviews.first {
type(of: $0) == NSClassFromString("_UIVisualEffectBackdropView")
}
}
var overlayView: UIView? {
base.subviews.first {
type(of: $0) == NSClassFromString("_UIVisualEffectSubview")
}
}
var gaussianBlurFilter: NSObject? {
backdropView?.arrayValue(getter: "filters")?.first {
$0.stringValue(getter: "filterType") == "gaussianBlur"
}
}
var sourceOverEffect: NSObject? {
overlayView?.arrayValue(getter: "viewEffects")?.first {
$0.stringValue(getter: "filterType") == "sourceOver"
}
}
// MARK: iOS 10, 11, 12
var blurEffect: NSObject? {
guard let effect = base.effect, type(of: effect) == NSClassFromString("_UICustomBlurEffect") else {
return nil
}
return base.effect
}
func updateBlurEffect(blurRadius: CGFloat, tintColor: UIColor?) {
let effect = (NSClassFromString("_UICustomBlurEffect") as? UIBlurEffect.Type)?.init()
effect?.setValueSafe(value: blurRadius, key: "blurRadius")
effect?.setValueSafe(value: tintColor ?? UIColor(white: 1.0, alpha: 0.3), key: "colorTint")
effect?.setValueSafe(value: 1.0, key: "scale")
effect?.setValueSafe(value: 1.0, key: "colorTintAlpha")
base.effect = effect
}
// MARK: Changes
func prepareForChanges() {
if #available(iOS 13, *) {
base.effect = UIBlurEffect(style: .light)
gaussianBlurFilter?.setIVarValue(value: 1.0, getter: "requestedScaleHint")
}
}
func applyChanges() {
if #available(iOS 13, *) {
backdropView?.callMethod(named: "applyRequestedFilterEffects")
}
}
}
@@ -0,0 +1,77 @@
//
// VisualEffectView+Public.swift
// Blurberry
//
// Created by Pavel Puzyrev on 09.09.2020.
//
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.
import UIKit
import ContainerControllerSwift
public extension BlurWrapper where Base: UIVisualEffectView {
var radius: CGFloat {
get {
if #available(iOS 13, *) {
return gaussianBlurFilter?.dictionaryValue(getter: "requestedValues")?["inputRadius"] as? CGFloat ?? 0.0
} else {
return blurEffect?.valueSafe(key: "blurRadius") as? CGFloat ?? 0.0
}
}
set {
prepareForChanges()
if #available(iOS 13, *) {
gaussianBlurFilter?.setObjectInDictionary(object: newValue, key: "inputRadius", getter: "requestedValues")
} else {
updateBlurEffect(blurRadius: newValue, tintColor: tintColor)
}
applyChanges()
}
}
var tintColor: UIColor? {
get {
if #available(iOS 13, *) {
return sourceOverEffect?.colorValue(getter: "color")
} else {
return blurEffect?.colorValue(getter: "colorTint")
}
}
set {
prepareForChanges()
if #available(iOS 13, *) {
sourceOverEffect?.setValueUsingSetter(value: newValue, getter: "color")
sourceOverEffect?.callMethod(named: "applyRequestedEffectToView:", with: overlayView)
} else {
updateBlurEffect(blurRadius: radius, tintColor: newValue)
}
applyChanges()
}
}
}
@@ -37,6 +37,7 @@ class Button: UIButton {
/// Simple tap implementation
typealias Closure = () -> ()
typealias ClosureClick = (_ down: Bool) -> ()
class ClosureSleeve {
@@ -59,5 +60,21 @@ extension UIControl {
sleeve,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
func tapClassic(_ closure: @escaping ClosureClick) {
self.tap(for: .touchDown) { // [weak self] in
closure(true)
}
self.tap(for: .touchUpInside) { // [weak self] in
closure(false)
}
self.tap(for: .touchUpOutside) { // [weak self] in
closure(false)
}
self.tap(for: .touchCancel) { // [weak self] in
closure(false)
}
}
}
@@ -60,7 +60,7 @@ class StoryboardController: UIViewController {
extension StoryboardController: ContainerControllerDelegate {
func addContainer(position: ContainerPosition, radius: CGFloat, items: [TableAdapterItem]? = nil, delegate: ContainerControllerDelegate? = nil, addShadow: Bool = true, addBackShadow: Bool = false, header: UIView? = nil, footer: UIView? = nil) -> (ContainerController, TableAdapterView) {
func addContainer(position: ContainerPosition, radius: CGFloat, items: [TableAdapterItem]? = nil, delegate: ContainerControllerDelegate? = nil, addShadow: Bool = true, addBackShadow: Bool = false, header: UIView? = nil, footer: UIView? = nil, back: UIView? = nil) -> (ContainerController, TableAdapterView) {
let layoutC = ContainerLayout()
layoutC.positions = position //
@@ -89,6 +89,8 @@ extension StoryboardController: ContainerControllerDelegate {
container.set(backgroundShadowShow: addBackShadow)
container.view.backgroundColor = .white
// container.view.backgroundColor = color
if let headerV = header {
@@ -99,6 +101,10 @@ extension StoryboardController: ContainerControllerDelegate {
container.add(footerView: footerV)
}
if let back = back {
container.backView?.addSubview(back)
}
let table = TableAdapterView(frame: CGRect(x: 0, y: 0, width: ContainerDevice.width, height: 0), style: .plain)
table.indicatorStyle = .default
// container.add(scrollView: addCollectionView())