mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge branch 'develop' into element_3452
This commit is contained in:
commit
4fff2887e4
18 changed files with 8 additions and 1055 deletions
1
Podfile
1
Podfile
|
@ -72,6 +72,7 @@ abstract_target 'RiotPods' do
|
|||
pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4'
|
||||
pod 'KTCenterFlowLayout', '~> 1.3.1'
|
||||
pod 'ZXingObjC', '~> 3.6.5'
|
||||
pod 'FlowCommoniOS', '~> 1.8.7'
|
||||
|
||||
target 'RiotTests' do
|
||||
inherit! :search_paths
|
||||
|
|
|
@ -38,6 +38,7 @@ PODS:
|
|||
- DTFoundation/Core
|
||||
- DTFoundation/UIKit (1.7.14):
|
||||
- DTFoundation/Core
|
||||
- FlowCommoniOS (1.8.7)
|
||||
- GBDeviceInfo (6.3.0):
|
||||
- GBDeviceInfo/Core (= 6.3.0)
|
||||
- GBDeviceInfo/Core (6.3.0)
|
||||
|
@ -107,6 +108,7 @@ PODS:
|
|||
DEPENDENCIES:
|
||||
- cmark
|
||||
- DGCollectionViewLeftAlignFlowLayout (~> 1.0.4)
|
||||
- FlowCommoniOS (~> 1.8.7)
|
||||
- GBDeviceInfo (~> 6.3.0)
|
||||
- KeychainAccess (~> 4.2)
|
||||
- KTCenterFlowLayout (~> 1.3.1)
|
||||
|
@ -130,6 +132,7 @@ SPEC REPOS:
|
|||
- DGCollectionViewLeftAlignFlowLayout
|
||||
- DTCoreText
|
||||
- DTFoundation
|
||||
- FlowCommoniOS
|
||||
- GBDeviceInfo
|
||||
- GZIP
|
||||
- HPGrowingTextView
|
||||
|
@ -155,6 +158,7 @@ SPEC CHECKSUMS:
|
|||
DGCollectionViewLeftAlignFlowLayout: a0fa58797373ded039cafba8133e79373d048399
|
||||
DTCoreText: 0298d372ccc137e51f27b3ec1af65fd4af5d173a
|
||||
DTFoundation: 25aa19bb7c6e225b1dfae195604fb8cf1da0ab4c
|
||||
FlowCommoniOS: 1647a1775b988f5d97202f635bcbcbce4f4c46a1
|
||||
GBDeviceInfo: a3f39dba1a04dcb630abff65d6f7e8fbf319eadd
|
||||
GZIP: af5c90ef903776a7e9afe6ebebd794a84a2929d4
|
||||
HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19
|
||||
|
@ -174,6 +178,6 @@ SPEC CHECKSUMS:
|
|||
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 4f5106309b0939cb9dca5512fc9880a78a8b4926
|
||||
PODFILE CHECKSUM: e717ca842bdc92972d5982a5b70032b9fe3ec9c2
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -148,19 +148,6 @@
|
|||
39D49C6524B8D40500FEDBC8 /* ElementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6224B8D40500FEDBC8 /* ElementViewController.swift */; };
|
||||
39D49C6624B8D40500FEDBC8 /* Timeline_1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6324B8D40500FEDBC8 /* Timeline_1.swift */; };
|
||||
39D49C6724B8D40500FEDBC8 /* ElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6424B8D40500FEDBC8 /* ElementView.swift */; };
|
||||
39D49C7724B8D42A00FEDBC8 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6A24B8D42900FEDBC8 /* UIImage+Extension.swift */; };
|
||||
39D49C7824B8D42A00FEDBC8 /* ShapeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6B24B8D42900FEDBC8 /* ShapeView.swift */; };
|
||||
39D49C7924B8D42A00FEDBC8 /* CAKeyframeAnimation+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6C24B8D42900FEDBC8 /* CAKeyframeAnimation+Extension.swift */; };
|
||||
39D49C7A24B8D42A00FEDBC8 /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6D24B8D42900FEDBC8 /* CATransaction+Extension.swift */; };
|
||||
39D49C7B24B8D42A00FEDBC8 /* CGPath+SVG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6E24B8D42900FEDBC8 /* CGPath+SVG.swift */; };
|
||||
39D49C7C24B8D42A00FEDBC8 /* CAMediaTimingFunction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6F24B8D42900FEDBC8 /* CAMediaTimingFunction+Extension.swift */; };
|
||||
39D49C7D24B8D42A00FEDBC8 /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7024B8D42900FEDBC8 /* Timeline.swift */; };
|
||||
39D49C7E24B8D42A00FEDBC8 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7124B8D42900FEDBC8 /* TextView.swift */; };
|
||||
39D49C7F24B8D42A00FEDBC8 /* NSMutableParagraphStyle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7224B8D42900FEDBC8 /* NSMutableParagraphStyle+Extension.swift */; };
|
||||
39D49C8024B8D42A00FEDBC8 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7324B8D42900FEDBC8 /* Animation.swift */; };
|
||||
39D49C8124B8D42A00FEDBC8 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7424B8D42900FEDBC8 /* UIView+Extension.swift */; };
|
||||
39D49C8224B8D42A00FEDBC8 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7524B8D42A00FEDBC8 /* Sound.swift */; };
|
||||
39D49C8324B8D42A00FEDBC8 /* NSShadow+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C7624B8D42A00FEDBC8 /* NSShadow+Extension.swift */; };
|
||||
3AF393339D2D566CE14AC200 /* Pods_RiotTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 129EB7E27E7E4AC3F5F098F5 /* Pods_RiotTests.framework */; };
|
||||
405FD41D306133A48D9B5AA1 /* Pods_RiotPods_Riot.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACF09217ADF1D7E7A35BC02 /* Pods_RiotPods_Riot.framework */; };
|
||||
670966FEFE120D865FD8A5B6 /* Pods_RiotPods_SiriIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51187E952D5CECF6D6F5A28E /* Pods_RiotPods_SiriIntents.framework */; };
|
||||
|
@ -1075,19 +1062,6 @@
|
|||
39D49C6224B8D40500FEDBC8 /* ElementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementViewController.swift; sourceTree = "<group>"; };
|
||||
39D49C6324B8D40500FEDBC8 /* Timeline_1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline_1.swift; sourceTree = "<group>"; };
|
||||
39D49C6424B8D40500FEDBC8 /* ElementView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementView.swift; sourceTree = "<group>"; };
|
||||
39D49C6A24B8D42900FEDBC8 /* UIImage+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+Extension.swift"; path = "FlowCommon/UIImage+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C6B24B8D42900FEDBC8 /* ShapeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShapeView.swift; path = FlowCommon/ShapeView.swift; sourceTree = "<group>"; };
|
||||
39D49C6C24B8D42900FEDBC8 /* CAKeyframeAnimation+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CAKeyframeAnimation+Extension.swift"; path = "FlowCommon/CAKeyframeAnimation+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C6D24B8D42900FEDBC8 /* CATransaction+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CATransaction+Extension.swift"; path = "FlowCommon/CATransaction+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C6E24B8D42900FEDBC8 /* CGPath+SVG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CGPath+SVG.swift"; path = "FlowCommon/CGPath+SVG.swift"; sourceTree = "<group>"; };
|
||||
39D49C6F24B8D42900FEDBC8 /* CAMediaTimingFunction+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CAMediaTimingFunction+Extension.swift"; path = "FlowCommon/CAMediaTimingFunction+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C7024B8D42900FEDBC8 /* Timeline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Timeline.swift; path = FlowCommon/Timeline.swift; sourceTree = "<group>"; };
|
||||
39D49C7124B8D42900FEDBC8 /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextView.swift; path = FlowCommon/TextView.swift; sourceTree = "<group>"; };
|
||||
39D49C7224B8D42900FEDBC8 /* NSMutableParagraphStyle+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSMutableParagraphStyle+Extension.swift"; path = "FlowCommon/NSMutableParagraphStyle+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C7324B8D42900FEDBC8 /* Animation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Animation.swift; path = FlowCommon/Animation.swift; sourceTree = "<group>"; };
|
||||
39D49C7424B8D42900FEDBC8 /* UIView+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Extension.swift"; path = "FlowCommon/UIView+Extension.swift"; sourceTree = "<group>"; };
|
||||
39D49C7524B8D42A00FEDBC8 /* Sound.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Sound.swift; path = FlowCommon/Sound.swift; sourceTree = "<group>"; };
|
||||
39D49C7624B8D42A00FEDBC8 /* NSShadow+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSShadow+Extension.swift"; path = "FlowCommon/NSShadow+Extension.swift"; sourceTree = "<group>"; };
|
||||
3D78489021AC9E6400B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
3D78489121AC9E6500B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
3D78489221AC9E6500B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Vector.strings; sourceTree = "<group>"; };
|
||||
|
@ -2432,26 +2406,6 @@
|
|||
name = LaunchLoadingAnimation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
39D49C6924B8D41A00FEDBC8 /* FlowCommon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
39D49C7324B8D42900FEDBC8 /* Animation.swift */,
|
||||
39D49C6C24B8D42900FEDBC8 /* CAKeyframeAnimation+Extension.swift */,
|
||||
39D49C6F24B8D42900FEDBC8 /* CAMediaTimingFunction+Extension.swift */,
|
||||
39D49C6D24B8D42900FEDBC8 /* CATransaction+Extension.swift */,
|
||||
39D49C6E24B8D42900FEDBC8 /* CGPath+SVG.swift */,
|
||||
39D49C7224B8D42900FEDBC8 /* NSMutableParagraphStyle+Extension.swift */,
|
||||
39D49C7624B8D42A00FEDBC8 /* NSShadow+Extension.swift */,
|
||||
39D49C6B24B8D42900FEDBC8 /* ShapeView.swift */,
|
||||
39D49C7524B8D42A00FEDBC8 /* Sound.swift */,
|
||||
39D49C7124B8D42900FEDBC8 /* TextView.swift */,
|
||||
39D49C7024B8D42900FEDBC8 /* Timeline.swift */,
|
||||
39D49C6A24B8D42900FEDBC8 /* UIImage+Extension.swift */,
|
||||
39D49C7424B8D42900FEDBC8 /* UIView+Extension.swift */,
|
||||
);
|
||||
name = FlowCommon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4220F60B660591FD80AF3428 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3513,7 +3467,6 @@
|
|||
B1B556CD20EE6C4C00210D55 /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
39D49C6924B8D41A00FEDBC8 /* FlowCommon */,
|
||||
EC85D7312477DD54002C44C9 /* SectionHeaders */,
|
||||
B183226923F59F3E0035B2E8 /* Buttons */,
|
||||
B1963B3622933B9500CBA17F /* CollectionView */,
|
||||
|
@ -5827,7 +5780,6 @@
|
|||
B12D7A0023E2462200FACEDC /* UserVerificationStartCoordinatorType.swift in Sources */,
|
||||
EC711B9324A63B37008F830C /* SecretsRecoveryWithKeyViewController.swift in Sources */,
|
||||
B1B5572220EE6C4D00210D55 /* RoomSettingsViewController.m in Sources */,
|
||||
39D49C7B24B8D42A00FEDBC8 /* CGPath+SVG.swift in Sources */,
|
||||
B1B5577320EE702800210D55 /* JitsiViewController.m in Sources */,
|
||||
B169331620F3CAFC00746532 /* PublicRoomsDirectoryDataSource.m in Sources */,
|
||||
B110871D21F087F4003554A5 /* KeyBackupSetupPassphraseViewState.swift in Sources */,
|
||||
|
@ -5849,9 +5801,7 @@
|
|||
EC711B9624A63B37008F830C /* SecretsRecoveryWithKeyViewState.swift in Sources */,
|
||||
B120863722EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift in Sources */,
|
||||
EC711B9224A63B37008F830C /* SecretsRecoveryWithKeyViewModel.swift in Sources */,
|
||||
39D49C7924B8D42A00FEDBC8 /* CAKeyframeAnimation+Extension.swift in Sources */,
|
||||
B1B5598620EFC3E000210D55 /* RiotSettings.swift in Sources */,
|
||||
39D49C8024B8D42A00FEDBC8 /* Animation.swift in Sources */,
|
||||
B1CE83D52422817200D07506 /* KeyVerificationVerifyByScanningViewController.swift in Sources */,
|
||||
EC711B8D24A63B37008F830C /* SecretsRecoveryGoal.swift in Sources */,
|
||||
3232ABA3225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift in Sources */,
|
||||
|
@ -5934,7 +5884,6 @@
|
|||
B1C3360222F1ED600021BA8D /* MediaPickerCoordinatorBridgePresenter.swift in Sources */,
|
||||
B1B558DF20EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
F083BE041E7009ED00A9B29C /* Tools.m in Sources */,
|
||||
39D49C8324B8D42A00FEDBC8 /* NSShadow+Extension.swift in Sources */,
|
||||
3275FD8C21A5A2C500B9C13D /* TermsView.swift in Sources */,
|
||||
B1B9DEE822EB34EF0065E677 /* ReactionHistoryCoordinatorType.swift in Sources */,
|
||||
EC711B7424A63B37008F830C /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */,
|
||||
|
@ -5953,7 +5902,6 @@
|
|||
B185145B24B8C98200EE19EA /* MajorUpdateViewController.swift in Sources */,
|
||||
32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */,
|
||||
B1B4E9BA24D46EB4004D5C33 /* SizableBubbleCell.swift in Sources */,
|
||||
39D49C7E24B8D42A00FEDBC8 /* TextView.swift in Sources */,
|
||||
32891D75226728EE00C82226 /* KeyVerificationDataLoadingViewController.swift in Sources */,
|
||||
F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */,
|
||||
B1B5581F20EF625800210D55 /* SimpleRoomTitleView.m in Sources */,
|
||||
|
@ -5998,7 +5946,6 @@
|
|||
B1B5582520EF638A00210D55 /* RoomMemberTitleView.m in Sources */,
|
||||
B1560DA224B65AFA00490F50 /* LaunchLoadingView.swift in Sources */,
|
||||
B1B5582C20EF666100210D55 /* DirectoryRecentTableViewCell.m in Sources */,
|
||||
39D49C8124B8D42A00FEDBC8 /* UIView+Extension.swift in Sources */,
|
||||
B1B558E420EF768F00210D55 /* RoomMembershipWithPaginationTitleBubbleCell.m in Sources */,
|
||||
B18DEDD8243377C10075FEF7 /* KeyVerificationSelfVerifyWaitCoordinatorType.swift in Sources */,
|
||||
B1B5573620EE6C4D00210D55 /* GroupsViewController.m in Sources */,
|
||||
|
@ -6089,7 +6036,6 @@
|
|||
B1B5574020EE6C4D00210D55 /* SegmentedViewController.m in Sources */,
|
||||
EC711BAE24A63B58008F830C /* SecureBackupSetupCoordinator.swift in Sources */,
|
||||
B1B5599320EFC5E400210D55 /* DecryptionFailure.m in Sources */,
|
||||
39D49C7D24B8D42A00FEDBC8 /* Timeline.swift in Sources */,
|
||||
B1CE83E12422817200D07506 /* KeyVerificationVerifyBySASCoordinator.swift in Sources */,
|
||||
EC619C1924DAD96000663A80 /* UIScrollView.swift in Sources */,
|
||||
B125FE1F231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift in Sources */,
|
||||
|
@ -6127,9 +6073,7 @@
|
|||
B1B5573220EE6C4D00210D55 /* GroupHomeViewController.m in Sources */,
|
||||
B1B5595220EF9A8700210D55 /* RecentTableViewCell.m in Sources */,
|
||||
B158253B2475350A00604D79 /* EventFormatter+DTCoreTextFix.m in Sources */,
|
||||
39D49C7F24B8D42A00FEDBC8 /* NSMutableParagraphStyle+Extension.swift in Sources */,
|
||||
EC711B9824A63B37008F830C /* SecretsRecoveryCoordinatorBridgePresenter.swift in Sources */,
|
||||
39D49C7A24B8D42A00FEDBC8 /* CATransaction+Extension.swift in Sources */,
|
||||
32F6B96C2270623100BBA352 /* KeyVerificationDataLoadingCoordinatorType.swift in Sources */,
|
||||
B14084CA23BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift in Sources */,
|
||||
B1DCC61D22E5E17100625807 /* EmojiPickerViewModelType.swift in Sources */,
|
||||
|
@ -6167,7 +6111,6 @@
|
|||
EC85D7372477DD97002C44C9 /* LocalContactsSectionHeaderContainerView.m in Sources */,
|
||||
B1DCC61A22E5E17100625807 /* EmojiPickerViewController.swift in Sources */,
|
||||
B1963B32228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift in Sources */,
|
||||
39D49C7824B8D42A00FEDBC8 /* ShapeView.swift in Sources */,
|
||||
EC1CA89A24C9C9A200DE9EBF /* SetupBiometricsCoordinatorType.swift in Sources */,
|
||||
32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */,
|
||||
B1098BFA21ECFE65000DDA48 /* KeyBackupSetupPassphraseViewModel.swift in Sources */,
|
||||
|
@ -6217,7 +6160,6 @@
|
|||
B1BEE74A23E093260003A4CB /* UserVerificationSessionStatusCoordinatorType.swift in Sources */,
|
||||
3232ABA4225730E100AD6A5C /* DeviceVerificationStartViewAction.swift in Sources */,
|
||||
B1550FCC2420E8F500CE097B /* QRCodeGenerator.swift in Sources */,
|
||||
39D49C8224B8D42A00FEDBC8 /* Sound.swift in Sources */,
|
||||
B1B5575A20EE6C4D00210D55 /* UnifiedSearchViewController.m in Sources */,
|
||||
3232AB492256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift in Sources */,
|
||||
B1B5572820EE6C4D00210D55 /* RoomViewController.m in Sources */,
|
||||
|
@ -6227,7 +6169,6 @@
|
|||
B1B9DEED22EB34EF0065E677 /* ReactionHistoryCoordinator.swift in Sources */,
|
||||
B1DCC62A22E60D1000625807 /* EmojiMartService.swift in Sources */,
|
||||
EC711BA924A63B58008F830C /* SecureBackupSetupCoordinatorBridgePresenter.swift in Sources */,
|
||||
39D49C7724B8D42A00FEDBC8 /* UIImage+Extension.swift in Sources */,
|
||||
B1B558C720EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */,
|
||||
B1B336C5242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewModel.swift in Sources */,
|
||||
EC9A3EC524E1616900A8CFAE /* PushNotificationManager.swift in Sources */,
|
||||
|
@ -6320,7 +6261,6 @@
|
|||
B18DEDDB243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewAction.swift in Sources */,
|
||||
32B94DF9228EC26400716A26 /* ReactionsMenuViewAction.swift in Sources */,
|
||||
B1B5599420EFC5E400210D55 /* DecryptionFailureTracker.m in Sources */,
|
||||
39D49C7C24B8D42A00FEDBC8 /* CAMediaTimingFunction+Extension.swift in Sources */,
|
||||
F083BDF01E7009ED00A9B29C /* UIViewController+RiotSearch.m in Sources */,
|
||||
32DB557522FDADE50016329E /* ServiceTermsModalCoordinatorType.swift in Sources */,
|
||||
F083BDF91E7009ED00A9B29C /* RoomEmailInvitation.m in Sources */,
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
open class Animation: NSObject, CAAnimationDelegate {
|
||||
/// Key frame animations which animate the properties of `layer`.
|
||||
fileprivate var keyframeAnimations: [CAKeyframeAnimation]
|
||||
|
||||
/// The CALayer whose properties are animated.
|
||||
open var layer: CALayer
|
||||
|
||||
/// Specifies whether or not the animation should autoreverse.
|
||||
var autoreverses: Bool
|
||||
|
||||
/// Determines the number of times the animation will repeat.
|
||||
///
|
||||
/// May be fractional. If the repeatCount is 0, it is ignored.
|
||||
/// Setting this property to greatestFiniteMagnitude will cause the animation to repeat forever.
|
||||
var repeatCount: Float
|
||||
|
||||
weak var delegate: AnimationDelegate?
|
||||
|
||||
/// The current time of the animation. i.e. what time is being displayed.
|
||||
var time: TimeInterval {
|
||||
return layer.timeOffset
|
||||
}
|
||||
|
||||
/// True if the animation is playing.
|
||||
var playing: Bool {
|
||||
return layer.speed != 0.0
|
||||
}
|
||||
|
||||
// MARK: - Initializers
|
||||
|
||||
public init(layer: CALayer, keyframeAnimations: [CAKeyframeAnimation], autoreverses: Bool = false, repeatCount: Float = 0) {
|
||||
self.layer = layer
|
||||
self.keyframeAnimations = keyframeAnimations
|
||||
self.autoreverses = autoreverses
|
||||
self.repeatCount = repeatCount
|
||||
|
||||
super.init()
|
||||
keyframeAnimations.forEach(configure)
|
||||
reset()
|
||||
}
|
||||
|
||||
private func configure(keyframeAnimation: CAKeyframeAnimation) {
|
||||
keyframeAnimation.delegate = self
|
||||
keyframeAnimation.isRemovedOnCompletion = false
|
||||
keyframeAnimation.fillMode = .both
|
||||
keyframeAnimation.autoreverses = autoreverses
|
||||
keyframeAnimation.repeatCount = repeatCount
|
||||
}
|
||||
|
||||
// MARK: - Playing & Resetting Animation
|
||||
|
||||
/// Resumes the animation from where it was paused.
|
||||
open func play() {
|
||||
let pausedTime = layer.timeOffset
|
||||
layer.speed = 1.0
|
||||
layer.timeOffset = 0.0
|
||||
layer.beginTime = 0.0
|
||||
let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
|
||||
layer.beginTime = timeSincePause
|
||||
}
|
||||
|
||||
/// Pauses the animation.
|
||||
open func pause() {
|
||||
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
|
||||
offset(to: pausedTime)
|
||||
}
|
||||
|
||||
/// Resets the animation to time 0.
|
||||
open func reset() {
|
||||
CATransaction.suppressAnimations {
|
||||
layer.removeAllAnimations()
|
||||
layer.beginTime = 0
|
||||
offset(to: 0)
|
||||
|
||||
for keyframeAnimation in keyframeAnimations {
|
||||
layer.setValue(keyframeAnimation.values?.first, forKeyPath: keyframeAnimation.keyPath!)
|
||||
}
|
||||
|
||||
addAllAnimations()
|
||||
layer.speed = 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds all the animations to `layer` so they can be played.
|
||||
private func addAllAnimations() {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let keyframeAnimations = self?.keyframeAnimations, let layer = self?.layer else {
|
||||
return
|
||||
}
|
||||
for keyframeAnimation in keyframeAnimations {
|
||||
layer.add(keyframeAnimation, forKey: keyframeAnimation.keyPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Driving Animation
|
||||
|
||||
/// Shows the animation at time `time`.
|
||||
open func offset(to time: TimeInterval) {
|
||||
layer.speed = 0.0
|
||||
layer.timeOffset = time
|
||||
}
|
||||
|
||||
// MARK: - CAAnimationDelegate
|
||||
|
||||
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
|
||||
guard flag else {
|
||||
return
|
||||
}
|
||||
|
||||
let time = autoreverses ? 0 : (keyframeAnimations.first?.duration ?? 0)
|
||||
offset(to: time)
|
||||
|
||||
if let keyframeAnimation = anim as? CAKeyframeAnimation,
|
||||
keyframeAnimations.first?.keyPath == keyframeAnimation.keyPath {
|
||||
delegate?.didStop(animation: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Animation {
|
||||
var reversed: Animation {
|
||||
let reversedKeyFrameAnimations = keyframeAnimations.map { $0.reversed }
|
||||
return Animation(layer: layer, keyframeAnimations: reversedKeyFrameAnimations)
|
||||
}
|
||||
}
|
||||
|
||||
protocol AnimationDelegate: class {
|
||||
func didStop(animation: Animation)
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
import UIKit
|
||||
|
||||
public extension CAKeyframeAnimation {
|
||||
var reversed: CAKeyframeAnimation {
|
||||
let reversed = CAKeyframeAnimation(keyPath: keyPath)
|
||||
reversed.keyTimes = keyTimes?.reversed().map { NSNumber(floatLiteral: 1.0 - $0.doubleValue) }
|
||||
reversed.values = values?.reversed()
|
||||
reversed.timingFunctions = timingFunctions?.reversed().map { $0.reversed }
|
||||
reversed.duration = duration
|
||||
return reversed
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
import UIKit
|
||||
|
||||
public extension CAMediaTimingFunction {
|
||||
static let linear = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
static let easeIn = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
|
||||
static let easeOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
|
||||
static let easeInEaseOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
|
||||
var reversed: CAMediaTimingFunction {
|
||||
let (c1, c2) = controlPoints
|
||||
let x1 = Float(1 - c2.x)
|
||||
let y1 = Float(1 - c2.y)
|
||||
let x2 = Float(1 - c1.x)
|
||||
let y2 = Float(1 - c1.y)
|
||||
return CAMediaTimingFunction(controlPoints: x1, y1, x2, y2)
|
||||
}
|
||||
|
||||
var controlPoints: (CGPoint, CGPoint) {
|
||||
var c1: [Float] = [0, 0]
|
||||
var c2: [Float] = [0, 0]
|
||||
getControlPoint(at: 1, values: &c1)
|
||||
getControlPoint(at: 2, values: &c2)
|
||||
|
||||
let c1x = CGFloat(c1[0])
|
||||
let c1y = CGFloat(c1[1])
|
||||
let c2x = CGFloat(c2[0])
|
||||
let c2y = CGFloat(c2[1])
|
||||
|
||||
return (CGPoint(x: c1x, y: c1y), CGPoint(x: c2x, y: c2y))
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
extension CATransaction {
|
||||
static public func suppressAnimations(actions: () -> Void) {
|
||||
begin()
|
||||
setAnimationDuration(0)
|
||||
actions()
|
||||
commit()
|
||||
}
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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 QuartzCore
|
||||
|
||||
public func CGPathCreateWithSVGString(_ string: String) -> CGPath? {
|
||||
let parser = SVGPathStringParser()
|
||||
return try? parser.parse(string)
|
||||
}
|
||||
|
||||
class SVGPathStringParser {
|
||||
enum Error: Swift.Error {
|
||||
case invalidSyntax
|
||||
case missingValues
|
||||
}
|
||||
|
||||
let path = CGMutablePath()
|
||||
var currentPoint = CGPoint()
|
||||
var lastControlPoint = CGPoint()
|
||||
|
||||
var command: UnicodeScalar?
|
||||
var values = [CGFloat]()
|
||||
|
||||
func parse(_ string: String) throws -> CGPath {
|
||||
let tokens = SVGPathStringTokenizer(string: string).tokenize()
|
||||
|
||||
for token in tokens {
|
||||
switch token {
|
||||
case .command(let c):
|
||||
command = c
|
||||
values.removeAll()
|
||||
|
||||
case .value(let v):
|
||||
values.append(v)
|
||||
}
|
||||
|
||||
do {
|
||||
try addCommand()
|
||||
} catch Error.missingValues {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
fileprivate func addCommand() throws {
|
||||
guard let command = command else {
|
||||
return
|
||||
}
|
||||
|
||||
switch command {
|
||||
case "M":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
path.move(to: CGPoint(x: values[0], y: values[1]))
|
||||
currentPoint = CGPoint(x: values[0], y: values[1])
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(2)
|
||||
|
||||
case "m":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
path.move(to: point)
|
||||
currentPoint.x += values[0]
|
||||
currentPoint.y += values[1]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(2)
|
||||
|
||||
case "L":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
let point = CGPoint(x: values[0], y: values[1])
|
||||
path.addLine(to: point)
|
||||
currentPoint = CGPoint(x: values[0], y: values[1])
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(2)
|
||||
|
||||
case "l":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
path.addLine(to: point)
|
||||
currentPoint.x += values[0]
|
||||
currentPoint.y += values[1]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(2)
|
||||
|
||||
case "H":
|
||||
if values.count < 1 { throw Error.missingValues }
|
||||
let point = CGPoint(x: values[0], y: currentPoint.y)
|
||||
path.addLine(to: point)
|
||||
currentPoint.x = values[0]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(1)
|
||||
|
||||
case "h":
|
||||
if values.count < 1 { throw Error.missingValues }
|
||||
let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y)
|
||||
path.addLine(to: point)
|
||||
currentPoint.x += values[0]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(1)
|
||||
|
||||
case "V":
|
||||
if values.count < 1 { throw Error.missingValues }
|
||||
let point = CGPoint(x: currentPoint.x, y: values[0])
|
||||
path.addLine(to: point)
|
||||
currentPoint.y = values[0]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(1)
|
||||
|
||||
case "v":
|
||||
if values.count < 1 { throw Error.missingValues }
|
||||
let point = CGPoint(x: currentPoint.x, y: currentPoint.y + values[0])
|
||||
path.addLine(to: point)
|
||||
currentPoint.y += values[0]
|
||||
lastControlPoint = currentPoint
|
||||
values.removeFirst(1)
|
||||
|
||||
case "C":
|
||||
if values.count < 6 { throw Error.missingValues }
|
||||
let c1 = CGPoint(x: values[0], y: values[1])
|
||||
let c2 = CGPoint(x: values[2], y: values[3])
|
||||
let to = CGPoint(x: values[4], y: values[5])
|
||||
path.addCurve(to: to, control1: c1, control2: c2)
|
||||
lastControlPoint = c2
|
||||
currentPoint = to
|
||||
values.removeFirst(6)
|
||||
|
||||
case "c":
|
||||
if values.count < 6 { throw Error.missingValues }
|
||||
let c1 = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
let c2 = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3])
|
||||
let to = CGPoint(x: currentPoint.x + values[4], y: currentPoint.y + values[5])
|
||||
path.addCurve(to: to, control1: c1, control2: c2)
|
||||
lastControlPoint = c2
|
||||
currentPoint = to
|
||||
values.removeFirst(6)
|
||||
|
||||
case "S":
|
||||
if values.count < 4 { throw Error.missingValues }
|
||||
var c1 = CGPoint()
|
||||
c1.x = currentPoint.x + (currentPoint.x - lastControlPoint.x)
|
||||
c1.y = currentPoint.y + (currentPoint.y - lastControlPoint.y)
|
||||
let c2 = CGPoint(x: values[0], y: values[1])
|
||||
let to = CGPoint(x: values[2], y: values[3])
|
||||
path.addCurve(to: to, control1: c1, control2: c2)
|
||||
lastControlPoint = c2
|
||||
currentPoint = to
|
||||
values.removeFirst(4)
|
||||
|
||||
case "s":
|
||||
if values.count < 4 { throw Error.missingValues }
|
||||
var c1 = CGPoint()
|
||||
c1.x = currentPoint.x + (currentPoint.x - lastControlPoint.x)
|
||||
c1.y = currentPoint.y + (currentPoint.y - lastControlPoint.y)
|
||||
let c2 = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
let to = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3])
|
||||
path.addCurve(to: to, control1: c1, control2: c2)
|
||||
lastControlPoint = c2
|
||||
currentPoint = to
|
||||
values.removeFirst(4)
|
||||
|
||||
case "Q":
|
||||
if values.count < 4 { throw Error.missingValues }
|
||||
let control = CGPoint(x: values[0], y: values[1])
|
||||
let to = CGPoint(x: values[2], y: values[3])
|
||||
path.addQuadCurve(to: to, control: control)
|
||||
lastControlPoint = control
|
||||
currentPoint = to
|
||||
values.removeFirst(4)
|
||||
|
||||
case "q":
|
||||
if values.count < 4 { throw Error.missingValues }
|
||||
let control = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
let to = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3])
|
||||
path.addQuadCurve(to: to, control: control)
|
||||
lastControlPoint = control
|
||||
currentPoint = to
|
||||
values.removeFirst(4)
|
||||
|
||||
case "T":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
var control = CGPoint()
|
||||
control.x = currentPoint.x + (currentPoint.x - lastControlPoint.x)
|
||||
control.y = currentPoint.y + (currentPoint.y - lastControlPoint.y)
|
||||
let to = CGPoint(x: values[0], y: values[1])
|
||||
path.addQuadCurve(to: to, control: control)
|
||||
lastControlPoint = control
|
||||
currentPoint = to
|
||||
values.removeFirst(2)
|
||||
|
||||
case "t":
|
||||
if values.count < 2 { throw Error.missingValues }
|
||||
var control = CGPoint()
|
||||
control.x = currentPoint.x + (currentPoint.x - lastControlPoint.x)
|
||||
control.y = currentPoint.y + (currentPoint.y - lastControlPoint.y)
|
||||
let to = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1])
|
||||
path.addQuadCurve(to: to, control: control)
|
||||
lastControlPoint = control
|
||||
currentPoint = to
|
||||
values.removeFirst(2)
|
||||
|
||||
case "Z", "z":
|
||||
path.closeSubpath()
|
||||
self.command = nil
|
||||
|
||||
default:
|
||||
throw Error.invalidSyntax
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SVGPathStringTokenizer {
|
||||
enum Token {
|
||||
case command(UnicodeScalar)
|
||||
case value(CGFloat)
|
||||
}
|
||||
|
||||
let separatorCharacterSet = CharacterSet(charactersIn: " \t\r\n,")
|
||||
let commandCharacterSet = CharacterSet(charactersIn: "mMLlHhVvzZCcSsQqTt")
|
||||
let numberStartCharacterSet = CharacterSet(charactersIn: "-+.0123456789")
|
||||
let numberCharacterSet = CharacterSet(charactersIn: ".0123456789eE")
|
||||
|
||||
var string: String
|
||||
var range: Range<String.UnicodeScalarView.Index>
|
||||
|
||||
init(string: String) {
|
||||
self.string = string
|
||||
range = string.unicodeScalars.startIndex..<string.unicodeScalars.endIndex
|
||||
}
|
||||
|
||||
func tokenize() -> [Token] {
|
||||
var array = [Token]()
|
||||
while let token = nextToken() {
|
||||
array.append(token)
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func nextToken() -> Token? {
|
||||
skipSeparators()
|
||||
|
||||
guard let c = get() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if commandCharacterSet.isMember(c) {
|
||||
return .command(c)
|
||||
}
|
||||
|
||||
if numberStartCharacterSet.isMember(c) {
|
||||
var numberString = String(c)
|
||||
while let c = peek(), numberCharacterSet.isMember(c) {
|
||||
numberString += String(c)
|
||||
get()
|
||||
}
|
||||
|
||||
if let value = Double(numberString) {
|
||||
return .value(CGFloat(value))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func get() -> UnicodeScalar? {
|
||||
guard range.lowerBound != range.upperBound else {
|
||||
return nil
|
||||
}
|
||||
let c = string.unicodeScalars[range.lowerBound]
|
||||
range = string.unicodeScalars.index(after: range.lowerBound)..<range.upperBound
|
||||
return c
|
||||
}
|
||||
|
||||
func peek() -> UnicodeScalar? {
|
||||
guard range.lowerBound != range.upperBound else {
|
||||
return nil
|
||||
}
|
||||
return string.unicodeScalars[range.lowerBound]
|
||||
}
|
||||
|
||||
func skipSeparators() {
|
||||
while range.lowerBound != range.upperBound && separatorCharacterSet.isMember(string.unicodeScalars[range.lowerBound]) {
|
||||
range = string.unicodeScalars.index(after: range.lowerBound)..<range.upperBound
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CharacterSet {
|
||||
public func isMember(_ c: UnicodeScalar) -> Bool {
|
||||
return contains(UnicodeScalar(c.value)!)
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
extension NSMutableParagraphStyle {
|
||||
convenience init(alignment: NSTextAlignment,
|
||||
firstLineHeadIndent: CGFloat,
|
||||
headIndent: CGFloat,
|
||||
tailIndent: CGFloat,
|
||||
lineHeightMultiple: CGFloat,
|
||||
maximumLineHeight: CGFloat,
|
||||
minimumLineHeight: CGFloat,
|
||||
lineSpacing: CGFloat,
|
||||
paragraphSpacing: CGFloat,
|
||||
paragraphSpacingBefore: CGFloat) {
|
||||
self.init()
|
||||
self.alignment = alignment
|
||||
self.firstLineHeadIndent = firstLineHeadIndent
|
||||
self.headIndent = headIndent
|
||||
self.tailIndent = tailIndent
|
||||
self.lineHeightMultiple = lineHeightMultiple
|
||||
self.maximumLineHeight = maximumLineHeight
|
||||
self.minimumLineHeight = minimumLineHeight
|
||||
self.lineSpacing = lineSpacing
|
||||
self.paragraphSpacing = paragraphSpacing
|
||||
self.paragraphSpacingBefore = paragraphSpacingBefore
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
extension NSShadow {
|
||||
convenience init(blurRadius: CGFloat, offset: CGSize, color: UIColor) {
|
||||
self.init()
|
||||
shadowBlurRadius = blurRadius
|
||||
shadowOffset = offset
|
||||
shadowColor = color
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT
|
||||
//
|
||||
// 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
|
||||
|
||||
open class ShapeView: UIView {
|
||||
open var shapeLayer: CAShapeLayer {
|
||||
return layer as! CAShapeLayer // swiftlint:disable:this force_cast
|
||||
}
|
||||
|
||||
/// A sublayer which can be used to apply a gradient fill to `self`.
|
||||
open var gradientLayer: CAGradientLayer? {
|
||||
set {
|
||||
// Remove old gradient layer
|
||||
if let gradientLayer = gradientLayer {
|
||||
gradientLayer.removeFromSuperlayer()
|
||||
}
|
||||
// Replace old gradient with new one
|
||||
if let newGradientLayer = newValue {
|
||||
layer.addSublayer(newGradientLayer)
|
||||
}
|
||||
}
|
||||
|
||||
get {
|
||||
return layer.sublayers?.first(where: { $0 is CAGradientLayer }) as? CAGradientLayer
|
||||
}
|
||||
}
|
||||
|
||||
public func addGradient(type: CAGradientLayerType, startPoint: CGPoint, endPoint: CGPoint, stops: [(color: CGColor, location: NSNumber)]) {
|
||||
let gradientLayer = CAGradientLayer()
|
||||
gradientLayer.frame = shapeLayer.bounds
|
||||
self.gradientLayer = gradientLayer
|
||||
|
||||
|
||||
let mask = CAShapeLayer()
|
||||
mask.path = shapeLayer.path
|
||||
mask.fillColor = UIColor.black.cgColor
|
||||
mask.strokeColor = nil
|
||||
|
||||
gradientLayer.startPoint = startPoint
|
||||
gradientLayer.endPoint = endPoint
|
||||
gradientLayer.colors = stops.map { $0.color }
|
||||
gradientLayer.locations = stops.map { $0.location }
|
||||
gradientLayer.type = type
|
||||
gradientLayer.frame = shapeLayer.bounds
|
||||
gradientLayer.mask = mask
|
||||
}
|
||||
|
||||
open var path: CGPath? {
|
||||
get {
|
||||
return shapeLayer.path
|
||||
}
|
||||
set {
|
||||
shapeLayer.path = newValue
|
||||
}
|
||||
}
|
||||
|
||||
override open class var layerClass: AnyClass {
|
||||
return CAShapeLayer.self
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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 AVFoundation
|
||||
|
||||
public final class Sound {
|
||||
|
||||
static func playAudio(_ audio: AVAudioPlayer, delay: TimeInterval) {
|
||||
audio.prepareToPlay()
|
||||
let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
|
||||
DispatchQueue.main.asyncAfter(deadline: time) {
|
||||
audio.play()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT
|
||||
//
|
||||
// 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
|
||||
|
||||
open class TextView: UILabel {
|
||||
open var textLayer: CATextLayer {
|
||||
return layer as! CATextLayer // swiftlint:disable:this force_cast
|
||||
}
|
||||
|
||||
override open class var layerClass: AnyClass {
|
||||
return CATextLayer.self
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
|
||||
open class Timeline {
|
||||
public var view: UIView
|
||||
public var duration: TimeInterval
|
||||
public let animations: [Animation]
|
||||
public let sounds: [(sound: AVAudioPlayer, delay: TimeInterval)]
|
||||
|
||||
/// Specifies whether or not the timeline's animations autoreverse.
|
||||
public let autoreverses: Bool
|
||||
|
||||
/// Determines the number of times the timeline's animations will repeat.
|
||||
///
|
||||
/// May be fractional. If the repeatCount is 0, it is ignored.
|
||||
/// Setting this property to greatestFiniteMagnitude will cause the timeline to repeat forever.
|
||||
public let repeatCount: Float
|
||||
|
||||
public var time: TimeInterval {
|
||||
return animations.first?.time ?? 0
|
||||
}
|
||||
|
||||
public var playing: Bool {
|
||||
return animations.first?.playing ?? false
|
||||
}
|
||||
|
||||
public weak var delegate: TimelineDelegate?
|
||||
|
||||
// MARK: - Initializers
|
||||
|
||||
public convenience init(view: UIView, animationsByLayer: [CALayer: [CAKeyframeAnimation]], sounds: [(sound: AVAudioPlayer, delay: TimeInterval)], duration: TimeInterval, autoreverses: Bool = false, repeatCount: Float = 0) {
|
||||
|
||||
let animations = animationsByLayer.map {
|
||||
Animation(layer: $0.0, keyframeAnimations: $0.1, autoreverses: autoreverses, repeatCount: repeatCount)
|
||||
}
|
||||
|
||||
self.init(view: view, animations: animations, sounds: sounds, duration: duration, autoreverses: autoreverses, repeatCount: repeatCount)
|
||||
}
|
||||
|
||||
init(view: UIView, animations: [Animation], sounds: [(sound: AVAudioPlayer, delay: TimeInterval)], duration: TimeInterval, autoreverses: Bool, repeatCount: Float) {
|
||||
self.view = view
|
||||
self.duration = duration
|
||||
self.sounds = sounds
|
||||
self.autoreverses = autoreverses
|
||||
self.repeatCount = repeatCount
|
||||
self.animations = animations
|
||||
self.animations.first?.delegate = self
|
||||
}
|
||||
|
||||
// MARK: - Timeline Playback controls
|
||||
|
||||
/// Reset to the initial state of the timeline
|
||||
public func reset() {
|
||||
for animation in animations {
|
||||
animation.reset()
|
||||
}
|
||||
delegate?.didReset(timeline: self)
|
||||
}
|
||||
|
||||
/// Resume playing the timeline.
|
||||
public func play() {
|
||||
playSounds()
|
||||
for animation in animations {
|
||||
animation.play()
|
||||
}
|
||||
delegate?.didPlay(timeline: self)
|
||||
}
|
||||
|
||||
private func playSounds() {
|
||||
for (sound, delay) in sounds {
|
||||
Sound.playAudio(sound, delay: delay)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pause playing of timeline.
|
||||
public func pause() {
|
||||
for animation in animations {
|
||||
animation.pause()
|
||||
}
|
||||
delegate?.didPause(timeline: self)
|
||||
}
|
||||
|
||||
/// Show timeline at time `time`.
|
||||
public func offset(to time: TimeInterval) {
|
||||
let time = max(min(time, duration), 0)
|
||||
for animation in animations {
|
||||
animation.offset(to: time)
|
||||
}
|
||||
delegate?.didOffset(timeline: self, to: time)
|
||||
}
|
||||
|
||||
/// Returns a reverses version of `self`.
|
||||
var reversed: Timeline {
|
||||
let reversedAnimations = animations.map { $0.reversed }
|
||||
return Timeline(view: view, animations: reversedAnimations, sounds: sounds, duration: duration, autoreverses: autoreverses, repeatCount: repeatCount)
|
||||
}
|
||||
}
|
||||
|
||||
extension Timeline: AnimationDelegate {
|
||||
func didStop(animation: Animation) {
|
||||
delegate?.didStop(timeline: self)
|
||||
}
|
||||
}
|
||||
|
||||
public protocol TimelineDelegate: class {
|
||||
/// Informs the delegate that the timeline `timeline` was reset.
|
||||
func didReset(timeline: Timeline)
|
||||
|
||||
/// Informs the delegate that the timeline `timeline` did start playing.
|
||||
func didPlay(timeline: Timeline)
|
||||
|
||||
/// Informs the delegate that the timeline `timeline` was paused.
|
||||
func didPause(timeline: Timeline)
|
||||
|
||||
/// Informs the delegate that the timeline `timeline` was offset.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - timeline: The timeline which was offset.
|
||||
/// - time: The time to which `timeline` was offset to.
|
||||
func didOffset(timeline: Timeline, to time: TimeInterval)
|
||||
|
||||
/// Informs the delegate that the timeline `timeline` was stopped because it completed its active duration.
|
||||
func didStop(timeline: Timeline)
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
extension UIImage {
|
||||
func resized(to size: CGSize) -> UIImage {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
let vertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height)
|
||||
return UIGraphicsImageRenderer(size: size).image { _ in
|
||||
let ctx = UIGraphicsGetCurrentContext()
|
||||
ctx?.saveGState()
|
||||
ctx?.concatenate(vertical)
|
||||
draw(in: rect)
|
||||
ctx?.restoreGState()
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright © 2016-2019 JABT Labs Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
extension UIView {
|
||||
func setTransform(scaleX: CGFloat, scaleY: CGFloat, rotationAngle: CGFloat) {
|
||||
var transform = CGAffineTransform.identity
|
||||
transform = transform.concatenating(CGAffineTransform(scaleX: scaleX, y: 1.0))
|
||||
transform = transform.concatenating(CGAffineTransform(scaleX: 1.0, y: scaleY))
|
||||
transform = transform.concatenating(CGAffineTransform(rotationAngle: rotationAngle))
|
||||
self.transform = transform
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import FlowCommoniOS
|
||||
|
||||
@IBDesignable
|
||||
public class ElementView: UIView {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// swiftlint:disable all
|
||||
|
||||
import UIKit
|
||||
import FlowCommoniOS
|
||||
|
||||
public class Timeline_1: Timeline {
|
||||
public convenience init(view: ElementView, duration: TimeInterval, autoreverses: Bool = false, repeatCount: Float = 0) {
|
||||
|
|
Loading…
Reference in a new issue