Commit c3f3177b by ludi

初步完成私房通话的代码编写,准备去掉原来的私房代码,接入新的私房代码

parent b7a17bf7
Showing with 1018 additions and 3 deletions
......@@ -11,6 +11,21 @@ NS_ASSUME_NONNULL_BEGIN
@interface FUSOCBaseView : UIView
/// 是否在触碰控制器区域时取消编辑,默认true
@property (nonatomic, assign) BOOL endEditingWhenTouch;
/// 是否点击穿透
@property (nonatomic, assign) BOOL transparency;
/// 判定是否穿透回调
@property (nonatomic, copy) BOOL(^transparencyHandler)(CGPoint);
/// 点击事件闭包
@property (nonatomic, copy) void(^touchHandler)(void);
/// 设置点击穿透区域,如果为zero则不设置
@property (nonatomic, assign) CGRect transparencyFrame;
- (void)makeUI;
- (void)bindViewModel;
......
......@@ -9,10 +9,28 @@
@implementation FUSOCBaseView
- (instancetype)init
{
self = [super init];
if (self) {
_endEditingWhenTouch = false;
_transparency = false;
_transparencyFrame = CGRectZero;
[self makeUI];
[self bindViewModel];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_endEditingWhenTouch = false;
_transparency = false;
_transparencyFrame = CGRectZero;
[self makeUI];
[self bindViewModel];
......@@ -29,4 +47,36 @@
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if (_endEditingWhenTouch) {
[self endEditing:true];
}
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if (_transparency && view == self) {
return nil;
}
if (!CGRectEqualToRect(_transparencyFrame, CGRectZero)) {
if (CGRectContainsPoint(_transparencyFrame, point)) {
return nil;
}
}
if (_transparencyHandler) {
BOOL shouldTransparency = _transparencyHandler(point);
if (shouldTransparency) {
return nil;
}
}
return view;
}
@end
//
// SPButton.h
// SPButton
//
// Created by 乐升平 on 2018/11/20.
// Copyright © 2018 乐升平. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, SPButtonImagePosition) {
SPButtonImagePositionLeft = 0, // 图片在文字左侧
SPButtonImagePositionRight = 1, // 图片在文字右侧
SPButtonImagePositionTop = 2, // 图片在文字上侧
SPButtonImagePositionBottom = 3 // 图片在文字下侧
};
IB_DESIGNABLE
@interface SPButton : UIButton
- (instancetype)initWithImagePosition:(SPButtonImagePosition)imagePosition;
#if TARGET_INTERFACE_BUILDER // storyBoard/xib中设置
@property (nonatomic,assign) IBInspectable NSInteger imagePosition; // 图片位置
@property (nonatomic, assign) IBInspectable CGFloat imageTitleSpace; // 图片和文字之间的间距
#else // 纯代码设置
@property (nonatomic) SPButtonImagePosition imagePosition; // 图片位置
@property (nonatomic, assign) CGFloat imageTitleSpace; // 图片和文字之间的间距
#endif
@end
NS_ASSUME_NONNULL_END
......@@ -24,5 +24,6 @@ typedef NS_ENUM(NSInteger,FUSRechargePageFrom) {
+ (void)fus_showRechargeViewControllerForRootVC:(UIViewController *)rootVC rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom;
+ (void)fus_showRechargeViewControllerForRootVC:(UIViewController *)rootVC from:(FUSFrom)from rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom;
+ (void)fus_showRechargeViewControllerForRootVC:(UIViewController *)rootVC from:(FUSFrom)from rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom backHandler:(void(^)(void))backHandler;
+ (FUSRechargeViewController *)fus_getAndShowRechargeViewControllerForRootVC:(UIViewController *)rootVC from:(FUSFrom)from rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom backHandler:(void(^)(void))backHandler;
@end
......@@ -96,6 +96,18 @@ NSString * const kEVENT_RECHARGE_OFFICIAL_PAGE_RETURN = @"officialrecharge_retur
[self fus_talkingDataEventWithFrom:from rechargePageFrom:rechargePageFrom isOfficial:YES];
}
+ (FUSRechargeViewController *)fus_getAndShowRechargeViewControllerForRootVC:(UIViewController *)rootVC from:(FUSFrom)from rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom backHandler:(void (^)(void))backHandler{
FUSRechargeViewController *vc = [[FUSRechargeViewController alloc] init];
vc.from = from;
vc.rechargePageFrom = rechargePageFrom;
vc.onClickBackHandle = backHandler;
[rootVC.navigationController pushViewController:vc animated:YES];
[self fus_talkingDataEventWithFrom:from rechargePageFrom:rechargePageFrom isOfficial:YES];
return vc;
}
+ (void)fus_talkingDataEventWithFrom:(FUSFrom)from
rechargePageFrom:(FUSRechargePageFrom)rechargePageFrom
isOfficial:(BOOL)isOfficial {
......
......@@ -65,6 +65,7 @@
#import "FUSSettingDataModel.h"
#import "FUSUserManagerVoiceSignModel.h"
#import "FUSRemindToDataModel.h"
#import "SPButton.h"
#import "FUSAliOSSModel.h"
#import "FUSAliOSSUploadFileModel.h"
#import "FUSMomentCreateModel.h"
......
......@@ -100,6 +100,12 @@ NS_ASSUME_NONNULL_BEGIN
success:(void (^)(void))success
failure:(void (^)(NSString *msg, int code))failure;
// 最小化直播间
- (void)fus_minimizeLiveCompletion: (void (^ __nullable)(void))completion;
// 最大化直播间
- (void)fus_maximizeLiveCompletion: (void (^ __nullable)(void))completion;
@end
NS_ASSUME_NONNULL_END
......@@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic,assign) FUSBeautyParameterFrom beautyViewFrom;
/// 消失
@property (nonatomic, copy) void(^fus_dismissComplete)(void);
/**
显示和隐藏
*/
......
......@@ -7,6 +7,38 @@
import UIKit
public func isValidString(_ str: String?) -> Bool {
if str?.count ?? 0 > 0 {
return true
} else {
return false
}
}
public func validString(_ str: String? , or replace: String) -> String {
if isValidString(str) {
return str!
} else {
return replace
}
}
public func isEmptyArr(_ arr: [Any]?) -> Bool {
if (arr?.count ?? 0) > 0 {
return false
} else {
return true
}
}
public func isEmptyDict(_ dict: [AnyHashable: Any]?) -> Bool {
if (dict?.count ?? 0) > 0 {
return false
} else {
return true
}
}
@objc public extension NSString{
@objc func fus_count() -> Int{
......@@ -20,3 +52,108 @@ import UIKit
return swiftString as NSString
}
}
public extension String {
// var md5 : String{
// let utf8 = cString(using: .utf8)
// var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
// CC_MD5(utf8, CC_LONG(utf8!.count - 1), &digest)
// return digest.reduce("") { $0 + String(format:"%02X", $1) }.lowercased()
// }
//Base64编码
func encodeBase64() -> String? {
return ObfuseTableBase64.inst()?.encode(self) ?? nil
}
//Base64解码
func decodeBase64() -> String? {
if self == "" {
return nil
}
return ObfuseTableBase64.inst()?.decode(self) ?? nil
}
static func base64urlToBase64(base64url: String) -> String {
var base64 = base64url
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
if base64.count % 4 != 0 {
base64.append(String(repeating: "=", count: 4 - base64.count % 4))
}
return base64
}
//将原始的url编码为合法的url
func urlEncoded() -> String {
return addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? ""
}
//将编码后的url转换回原始的url
func urlDecoded() -> String {
return self.removingPercentEncoding ?? self
}
var intValue: Int {
return Int(self) ?? 0
}
var int: Int? {
return Int(self)
}
var doubleValue: Double {
return Double(self) ?? 0.0
}
var double: Double? {
return Double(self)
}
var uint: UInt? {
return UInt(self)
}
var uintValue: UInt {
return UInt(self) ?? 0
}
var boolValue: Bool {
if self.intValue > 0 || self.lowercased() == "yes" || self.lowercased() == "true" {
return true
} else {
return false
}
}
var pinyin: String? {
let str = NSMutableString(string: self)
CFStringTransform(str, nil, kCFStringTransformToLatin, false)
str.folding(options: .diacriticInsensitive, locale: Locale.current)
return str.replacingOccurrences(of: "'", with: "")
}
var ya_length: Int {
let encodeValue = CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncodings.GB_18030_2000.rawValue))
let encode = String.Encoding.init(rawValue: encodeValue)
return self.lengthOfBytes(using: encode)
}
}
public extension [String: Any] {
func fus_intValue(key: String) -> Int {
if let rltValue = self[key] as? Int {
return rltValue
}
return 0
}
func fus_stringValue(key: String) -> String {
if let rltValue = self[key] as? String {
return rltValue
}
return ""
}
}
//
// UIImageView+FUSWebImage.swift
// FUSFoundation
//
// Created by aaa on 2024/12/11.
//
import UIKit
import RxSwift
/// Rx 封装
public extension Reactive where Base: UIImageView {
/// 绑定图片地址
var fus_imageUrl: Binder<String?> {
return .init(base) { target, imageUrl in
target.setWebImageWithSubURLString(imageUrl, placeholder: .fus_defaultIcon())
}
}
}
//
// UIViewSwiftExt.swift
// FUSFoundation
//
// Created by aaa on 2024/12/12.
//
import UIKit
public extension UIView {
@objc public var maxY : CGFloat { self.y + self.height }
@objc public var maxX : CGFloat { self.x + self.width }
}
//
// UIWindowSwiftExt.swift
// FUSFoundation
//
// Created by aaa on 2024/12/12.
//
import UIKit
public extension UIWindow {
/// 当前window
@objc static public var fus_keyWindow: UIWindow? {
if #available(iOS 13.0, *) {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
return windowScene.windows.first(where: { $0.isKeyWindow })
}else {
return nil
}
}else {
return UIApplication.shared.keyWindow
}
}
}
......@@ -69,6 +69,12 @@ typedef NS_OPTIONS(NSInteger, FUSLogFlag){
*/
+ (void)logWithFlag:(FUSLogFlag)flag message:(NSString *)content, ...;
+ (void)error:(id)content;
+ (void)info:(id)content;
+ (void)warn:(id)content;
+ (void)debug:(id)content;
+ (void)verbose:(id)content;
@end
NS_ASSUME_NONNULL_END
......@@ -67,4 +67,24 @@ static FUSLogLevel kfusLogLevel = FUSLogLevelOff;
}
}
+ (void)error:(id)content {
FUSLogError(@"%@", content);
}
+ (void)info:(id)content {
FUSLogInfo(@"%@", content);
}
+ (void)warn:(id)content {
FUSLogWarn(@"%@", content);
}
+ (void)debug:(id)content {
FUSLogDebug(@"%@", content);
}
+ (void)verbose:(id)content {
FUSLogVerbose(@"%@", content);
}
@end
//
// FFCallRaderFaceView.swift
// SingleChat
//
// Created by Jim Chan on 2022/8/31.
//
import UIKit
import RxSwift
import RxCocoa
@objcMembers public class FUSRadarFaceView: UIView {
let disposeBag = DisposeBag()
@objc public var maxRadarScale: CGFloat
@objc public var radarSpeed: CGFloat
@objc public var radarCount: Int
@objc public var radarColor: UIColor
public let faceUrl = BehaviorRelay<String?>(value: nil)
@objc public func setupFaceUrl(faceUrl:String) {
self.faceUrl.accept(faceUrl)
}
@objc public func setupImage(image:UIImage?) {
self.faceImageView.image = image
}
public override var frame: CGRect {
didSet {
faceImageView.frame = self.bounds
faceImageView.layer.cornerRadius = faceImageView.height / 2.0
for layer in shapeLayers {
layer.center = faceImageView.center
}
}
}
// MARK: Init
@objc public init(radarCount: Int = 5, radarSpeed: CGFloat = 3.0, radarScale: CGFloat = 2, radarColor: UIColor = UIColor(hexString: "34E7E0") ?? .white) {
self.maxRadarScale = radarScale
self.radarSpeed = radarSpeed
self.radarCount = radarCount
self.radarColor = radarColor
super.init(frame: .init(x: 0, y: 0, width: 180, height: 180))
makeUI()
bindViewModel()
setupNotification()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: UI
func makeUI() {
self.backgroundColor = .clear
faceImageView.contentMode = .scaleAspectFill
faceImageView.layer.masksToBounds = true
faceImageView.layer.cornerRadius = 90
faceImageView.bounds = .init(x: 0, y: 0, width: 180, height: 180)
self.addSubview(faceImageView)
}
private let faceImageView = UIImageView(image: nil)
private var shapeLayers = [CAShapeLayer]()
public let isAnimating = BehaviorRelay<Bool>(value: false)
public override func layoutSubviews() {
super.layoutSubviews()
faceImageView.layer.cornerRadius = faceImageView.height / 2.0
}
// MARK: Data
func bindViewModel() {
faceUrl.subscribe(onNext: {[weak self] imageUrl in
self?.faceImageView.setWebImageWithSubURLString(imageUrl)
})
.disposed(by: disposeBag)
}
// MARK: Method
@objc public func startAnimation() {
guard isAnimating.value == false else { return }
stopAnimation()
self.isAnimating.accept(true)
for i in 0..<radarCount {
let radius = faceImageView.height / 2.0
let centerPoint = faceImageView.center
let path = UIBezierPath(arcCenter: centerPoint, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.frame = self.bounds
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = radarColor.cgColor
shapeLayer.opacity = 1
shapeLayer.path = path.cgPath
shapeLayer.lineWidth = 1.5
self.shapeLayers.append(shapeLayer)
self.layer.insertSublayer(shapeLayer, below: faceImageView.layer)
// 动画
let pathAni = CABasicAnimation()
pathAni.keyPath = "path"
let path1 = UIBezierPath(arcCenter: centerPoint, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
let path2 = UIBezierPath(arcCenter: centerPoint, radius: radius * maxRadarScale, startAngle: 0, endAngle: .pi * 2, clockwise: true)
pathAni.fromValue = path1.cgPath
pathAni.toValue = path2.cgPath
pathAni.fillMode = .forwards
let opacityAni = CABasicAnimation()
opacityAni.keyPath = "opacity"
opacityAni.fromValue = 1
opacityAni.toValue = 0
opacityAni.fillMode = .forwards
let group = CAAnimationGroup()
group.animations = [pathAni, opacityAni]
// 动画间隔时间 这里的值和创建的动画个数需要计算好,避免最后一轮动画结束了,第一个动画好没有结束,出现效果差
let totalTime = CGFloat(radarCount) / radarSpeed
group.duration = totalTime
group.beginTime = CACurrentMediaTime() + totalTime * (CGFloat(i) / CGFloat(radarCount))
group.repeatCount = .infinity
group.timingFunction = .init(name: .easeOut)
group.isRemovedOnCompletion = true
shapeLayer.add(group, forKey: nil)
}
}
@objc public func stopAnimation() {
self.isAnimating.accept(false)
for layer in shapeLayers {
layer.removeAllAnimations()
layer.removeFromSuperlayer()
}
shapeLayers.removeAll()
}
// MARK: Notification
func setupNotification() {
NotificationCenter.default.rx.notification(UIApplication.didBecomeActiveNotification).subscribe(onNext: {[weak self] _ in
guard let self = self else { return }
if self.isAnimating.value == true {
self.stopAnimation()
self.startAnimation()
}
}).disposed(by: disposeBag)
}
}
......@@ -18,7 +18,7 @@ typedef NS_ENUM(NSInteger, FUSButtonStyle) {
FUSButtonStyleWhiteBorder, // 纯白边框样式(没背景,没圆角)
FUSButtonStyleGrayBorder, // 白边 灰色底 (自带圆角)
FUSButtonStyleBlurGradientBorder, // 彩色渐变边框 和 渐变模糊透明背景(自带圆角)
FUSButtonStyleBlue, // 纯色背景
FUSButtonStyleBlue, // 纯色背景,一般蓝底黑字用这个
FUSButtonStyleBlueBorder, // 纯色背景
};
......
......@@ -421,6 +421,10 @@
- (void)didCaptureVideoSampleBuffer:(CMSampleBufferRef)videoBuffer {
if (self.viewDidShowed == NO) {
return;
}
CVPixelBufferRef buffer = CMSampleBufferGetImageBuffer(videoBuffer);
CMTime pts = CMSampleBufferGetPresentationTimeStamp(videoBuffer);
......
......@@ -48,6 +48,9 @@ typedef NS_ENUM(NSInteger, FUSStreamSessionState)
// 是否镜像
@property (nonatomic, assign) BOOL videoMirror;
// 页面是否完全展示
@property (nonatomic, assign) BOOL viewDidShowed;
@property (nonatomic, strong) NSString *pushUrl;
// 持有完成回调
......
......@@ -70,6 +70,11 @@ NSString * const kStreamRTCDidOfflineNotification = @"kStreamRTCDidOfflineNotifi
_streamType = FUSStreamTypeSingleStream;
[self initCaptureHelper];
/// 需要等View完全展示才能开始采集,不然有可能会闪退
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.captureHelper.viewDidShowed = YES;
});
}
return self;
}
......
......@@ -7,12 +7,12 @@
<key>FUSChatCenterBundle.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>73</integer>
<integer>76</integer>
</dict>
<key>FUSChatCenterModule.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>77</integer>
<integer>74</integer>
</dict>
</dict>
</dict>
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callCenter_EndCall_FreeTime_title_Img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callCenter_EndCall_FreeTime_title_Img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callCenter_freeTimeIsUp_title_img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callCenter_freeTimeIsUp_title_img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callCenter_icon_close@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callCenter_icon_close@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callCenter_portrait_follow_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callCenter_portrait_follow_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callCenter_portrait_follow_selected_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callCenter_portrait_follow_selected_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_call_accept@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_call_accept@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_call_accept_video@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_call_accept_video@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_call_refuse@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_function_icon_gift_highlight@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_function_icon_gift_highlight@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_function_icon_gift_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_function_icon_gift_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_function_icon_minimize@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_function_icon_minimize@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_function_icon_setting@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_function_icon_setting@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_beauty_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_beauty_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_beauty_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_beauty_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_camera_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_camera_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_camera_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_camera_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_flashLight_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_flashLight_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_flashLight_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_flashLight_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_mic_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_mic_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_mic_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_mic_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_sound_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_sound_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_sound_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callHelper_oneToOne_panel_icon_sound_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment